ifconfig(8): Use correct interface name when setting flags
[dragonfly.git] / share / examples / scsi_target / scsi_cmds.c
1 /*
2  * SCSI Disk Emulator
3  *
4  * Copyright (c) 2002 Nate Lawson.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions, and the following disclaimer,
12  *    without modification, immediately at the beginning of the file.
13  * 2. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD: src/share/examples/scsi_target/scsi_cmds.c,v 1.2.2.1 2003/02/18 22:07:10 njl Exp $
29  */
30
31 #include <stdio.h>
32 #include <stddef.h>
33 #include <stdarg.h>
34 #include <string.h>
35 #include <err.h>
36 #include <aio.h>
37 #include <assert.h>
38 #include <sys/types.h>
39
40 #include <bus/cam/cam.h>
41 #include <bus/cam/cam_ccb.h>
42 #include <bus/cam/scsi/scsi_all.h>
43 #include <bus/cam/scsi/scsi_targetio.h>
44 #include "scsi_target.h"
45
46 typedef int targ_start_func(struct ccb_accept_tio *, struct ccb_scsiio *);
47 typedef void targ_done_func(struct ccb_accept_tio *, struct ccb_scsiio *,
48                               io_ops);
49
50 struct targ_cdb_handlers {
51         u_int8_t          cmd;
52         targ_start_func  *start;
53         targ_done_func   *done;
54 #define ILLEGAL_CDB       0xFF
55 };
56
57 static targ_start_func          tcmd_inquiry;
58 static targ_start_func          tcmd_req_sense;
59 static targ_start_func          tcmd_rd_cap;
60 static targ_start_func          tcmd_rdwr;
61 static targ_start_func          tcmd_rdwr_decode;
62 static targ_done_func           tcmd_rdwr_done;
63 static targ_start_func          tcmd_null_ok;
64 static targ_start_func          tcmd_illegal_req;
65 static int                      start_io(struct ccb_accept_tio *atio,
66                                          struct ccb_scsiio *ctio, int dir);
67 static int init_inquiry(u_int16_t req_flags, u_int16_t sim_flags);
68 static struct initiator_state *
69                         tcmd_get_istate(u_int init_id);
70 static void cdb_debug(u_int8_t *cdb, const char *msg, ...);
71
72 static struct targ_cdb_handlers cdb_handlers[] = { 
73         { READ_10,              tcmd_rdwr,              tcmd_rdwr_done },
74         { WRITE_10,             tcmd_rdwr,              tcmd_rdwr_done },
75         { READ_6,               tcmd_rdwr,              tcmd_rdwr_done },
76         { WRITE_6,              tcmd_rdwr,              tcmd_rdwr_done },
77         { INQUIRY,              tcmd_inquiry,           NULL },
78         { REQUEST_SENSE,        tcmd_req_sense,         NULL },
79         { READ_CAPACITY,        tcmd_rd_cap,            NULL },
80         { TEST_UNIT_READY,      tcmd_null_ok,           NULL },
81         { START_STOP_UNIT,      tcmd_null_ok,           NULL },
82         { SYNCHRONIZE_CACHE,    tcmd_null_ok,           NULL },
83         { MODE_SENSE_6,         tcmd_illegal_req,       NULL },
84         { MODE_SELECT_6,        tcmd_illegal_req,       NULL },
85         { ILLEGAL_CDB,          NULL,                   NULL }
86 };
87
88 static struct scsi_inquiry_data inq_data;
89 static struct initiator_state istates[MAX_INITIATORS];
90 extern int              debug;
91 extern u_int32_t        volume_size;
92 extern size_t           sector_size;
93 extern size_t           buf_size;
94
95 cam_status
96 tcmd_init(u_int16_t req_inq_flags, u_int16_t sim_inq_flags)
97 {
98         struct initiator_state *istate;
99         int i, ret;
100
101         /* Initialize our inquiry data */
102         ret = init_inquiry(req_inq_flags, sim_inq_flags);
103         if (ret != 0)
104                 return (ret);
105
106         /* We start out life with a UA to indicate power-on/reset. */
107         for (i = 0; i < MAX_INITIATORS; i++) {
108                 istate = tcmd_get_istate(i);
109                 bzero(istate, sizeof(*istate));
110                 istate->pending_ua = UA_POWER_ON;
111         }
112
113         return (0);
114 }
115
116 /* Caller allocates CTIO, sets its init_id
117 return 0 if done, 1 if more processing needed 
118 on 0, caller sets SEND_STATUS */
119 int
120 tcmd_handle(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio, io_ops event)
121 {
122         static struct targ_cdb_handlers *last_cmd; 
123         struct initiator_state *istate;
124         struct atio_descr *a_descr;
125         int ret;
126
127         if (debug) {
128                 warnx("tcmd_handle atio %p ctio %p atioflags %#x", atio, ctio,
129                       atio->ccb_h.flags);
130         }
131         ret = 0;
132         a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
133
134         /* Do a full lookup if one-behind cache failed */
135         if (last_cmd == NULL || last_cmd->cmd != a_descr->cdb[0]) {
136                 struct targ_cdb_handlers *h; 
137
138                 for (h = cdb_handlers; h->cmd != ILLEGAL_CDB; h++) {
139                         if (a_descr->cdb[0] == h->cmd)
140                                 break;
141                 }
142                 last_cmd = h;
143         }
144         if (last_cmd->cmd == ILLEGAL_CDB) {
145                 if (event != ATIO_WORK) {
146                         warnx("no done func for %#x???", a_descr->cdb[0]);
147                         abort();
148                 }
149                 /* Not found, return illegal request */
150                 warnx("cdb %#x not handled", a_descr->cdb[0]);
151                 tcmd_illegal_req(atio, ctio);
152                 send_ccb((union ccb *)ctio, /*priority*/1);
153                 return (0);
154         }
155
156         /* call completion and exit */
157         if (event != ATIO_WORK) {
158                 if (last_cmd->done != NULL)
159                         last_cmd->done(atio, ctio, event);
160                 else
161                         free_ccb((union ccb *)ctio);
162                 return (1);
163         }
164
165         istate = tcmd_get_istate(ctio->init_id);
166         if (istate == NULL) {
167                 tcmd_illegal_req(atio, ctio);
168                 send_ccb((union ccb *)ctio, /*priority*/1);
169                 return (0);
170         }
171
172         if (istate->pending_ca == 0 && istate->pending_ua != 0 &&
173             a_descr->cdb[0] != INQUIRY) {
174                 tcmd_sense(ctio->init_id, ctio, SSD_KEY_UNIT_ATTENTION,
175                            0x29, istate->pending_ua == UA_POWER_ON ? 1 : 2);
176                 istate->pending_ca = CA_UNIT_ATTN;
177                 if (debug) {
178                         cdb_debug(a_descr->cdb, "UA active for %u: ",
179                                   atio->init_id);
180                 }
181                 send_ccb((union ccb *)ctio, /*priority*/1);
182                 return (0);
183         } 
184
185         /* Store current CA and UA for later */
186         istate->orig_ua = istate->pending_ua;
187         istate->orig_ca = istate->pending_ca;
188
189         /*
190          * As per SAM2, any command that occurs
191          * after a CA is reported, clears the CA.  We must
192          * also clear the UA condition, if any, that caused
193          * the CA to occur assuming the UA is not for a
194          * persistent condition.
195          */
196         istate->pending_ca = CA_NONE;
197         if (istate->orig_ca == CA_UNIT_ATTN)
198                 istate->pending_ua = UA_NONE;
199
200         /* If we have a valid handler, call start or completion function */
201         if (last_cmd->cmd != ILLEGAL_CDB) {
202                 ret = last_cmd->start(atio, ctio);
203                 /* XXX hack */
204                 if (last_cmd->start != tcmd_rdwr) {
205                         a_descr->init_req += ctio->dxfer_len;
206                         send_ccb((union ccb *)ctio, /*priority*/1);
207                 }
208         }
209
210         return (ret);
211 }
212
213 static struct initiator_state *
214 tcmd_get_istate(u_int init_id)
215 {
216         if (init_id >= MAX_INITIATORS) {
217                 warnx("illegal init_id %d, max %d", init_id, MAX_INITIATORS - 1);
218                 return (NULL);
219         } else {
220                 return (&istates[init_id]);
221         }
222 }
223
224 void
225 tcmd_sense(u_int init_id, struct ccb_scsiio *ctio, u_int8_t flags,
226                u_int8_t asc, u_int8_t ascq)
227 {
228         struct initiator_state *istate;
229         struct scsi_sense_data *sense;
230
231         /* Set our initiator's istate */
232         istate = tcmd_get_istate(init_id);
233         if (istate == NULL)
234                 return;
235         istate->pending_ca |= CA_CMD_SENSE; /* XXX set instead of or? */
236         sense = &istate->sense_data;
237         bzero(sense, sizeof(*sense));
238         sense->error_code = SSD_CURRENT_ERROR;
239         sense->flags = flags;
240         sense->add_sense_code = asc;
241         sense->add_sense_code_qual = ascq;
242         sense->extra_len =
243                 offsetof(struct scsi_sense_data, sense_key_spec[2]) -
244                 offsetof(struct scsi_sense_data, extra_len);
245
246         /* Fill out the supplied CTIO */
247         if (ctio != NULL) {
248                 /* No autosense yet
249                 bcopy(sense, &ctio->sense_data, sizeof(*sense));
250                 ctio->sense_len = sizeof(*sense);  XXX
251                 */
252                 ctio->ccb_h.flags &= ~CAM_DIR_MASK;
253                 ctio->ccb_h.flags |= CAM_DIR_NONE | /* CAM_SEND_SENSE | */
254                                      CAM_SEND_STATUS;
255                 ctio->dxfer_len = 0;
256                 ctio->scsi_status = SCSI_STATUS_CHECK_COND;
257         }
258 }
259
260 void
261 tcmd_ua(u_int init_id, ua_types new_ua)
262 {
263         struct initiator_state *istate;
264         u_int start, end;
265
266         if (init_id == CAM_TARGET_WILDCARD) {
267                 start = 0;
268                 end = MAX_INITIATORS - 1;
269         } else {
270                 start = end = init_id;
271         }
272
273         for (; start <= end; start++) {
274                 istate = tcmd_get_istate(start);
275                 if (istate == NULL)
276                         break;
277                 istate->pending_ua = new_ua;
278         }
279 }
280
281 static int
282 tcmd_inquiry(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
283 {
284         struct scsi_inquiry *inq;
285         struct atio_descr *a_descr;
286         struct initiator_state *istate;
287         struct scsi_sense_data *sense;
288
289         a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
290         inq = (struct scsi_inquiry *)a_descr->cdb;
291
292         if (debug)
293                 cdb_debug(a_descr->cdb, "INQUIRY from %u: ", atio->init_id);
294         /*
295          * Validate the command.  We don't support any VPD pages, so
296          * complain if EVPD or CMDDT is set.
297          */
298         istate = tcmd_get_istate(ctio->init_id);
299         sense = &istate->sense_data;
300         if ((inq->byte2 & SI_EVPD) != 0) {
301                 tcmd_illegal_req(atio, ctio);
302                 sense->sense_key_spec[0] = SSD_SCS_VALID | SSD_FIELDPTR_CMD |
303                         SSD_BITPTR_VALID | /*bit value*/1;
304                 sense->sense_key_spec[1] = 0;
305                 sense->sense_key_spec[2] =
306                         offsetof(struct scsi_inquiry, byte2);
307         } else if (inq->page_code != 0) {
308                 tcmd_illegal_req(atio, ctio);
309                 sense->sense_key_spec[0] = SSD_SCS_VALID | SSD_FIELDPTR_CMD;
310                 sense->sense_key_spec[1] = 0;
311                 sense->sense_key_spec[2] =
312                         offsetof(struct scsi_inquiry, page_code);
313         } else {
314                 bcopy(&inq_data, ctio->data_ptr, sizeof(inq_data));
315                 ctio->dxfer_len = inq_data.additional_length + 4;
316                 ctio->dxfer_len = min(ctio->dxfer_len,
317                                       SCSI_CDB6_LEN(inq->length));
318                 ctio->ccb_h.flags |= CAM_DIR_IN | CAM_SEND_STATUS;
319                 ctio->scsi_status = SCSI_STATUS_OK;
320         }
321         return (0);
322 }
323
324 /* Initialize the inquiry response structure with the requested flags */
325 static int
326 init_inquiry(u_int16_t req_flags, u_int16_t sim_flags)
327 {
328         struct scsi_inquiry_data *inq;
329
330         inq = &inq_data;
331         bzero(inq, sizeof(*inq));
332         inq->device = T_DIRECT | (SID_QUAL_LU_CONNECTED << 5);
333         inq->version = SCSI_REV_3; /* was 2 */
334
335         /*
336          * XXX cpi.hba_inquiry doesn't support Addr16 so we give the
337          * user what they want if they ask for it.
338          */
339         if ((req_flags & SID_Addr16) != 0) {
340                 sim_flags |= SID_Addr16;
341                 warnx("Not sure SIM supports Addr16 but enabling it anyway");
342         }
343
344         /* Advertise only what the SIM can actually support */
345         req_flags &= sim_flags;
346         scsi_ulto2b(req_flags, &inq->reserved[1]);
347
348         inq->response_format = 2; /* SCSI2 Inquiry Format */
349         inq->additional_length = SHORT_INQUIRY_LENGTH -
350                 offsetof(struct scsi_inquiry_data, additional_length);
351         bcopy("FreeBSD ", inq->vendor, SID_VENDOR_SIZE);
352         bcopy("Emulated Disk   ", inq->product, SID_PRODUCT_SIZE);
353         bcopy("0.1 ", inq->revision, SID_REVISION_SIZE);
354         return (0);
355 }
356
357 static int
358 tcmd_req_sense(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
359 {
360         struct scsi_request_sense *rsense;
361         struct scsi_sense_data *sense;
362         struct initiator_state *istate;
363         size_t dlen;
364         struct atio_descr *a_descr;
365
366         a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
367         rsense = (struct scsi_request_sense *)a_descr->cdb;
368         
369         istate = tcmd_get_istate(ctio->init_id);
370         sense = &istate->sense_data;
371
372         if (debug) {
373                 cdb_debug(a_descr->cdb, "REQ SENSE from %u: ", atio->init_id);
374                 warnx("Sending sense: %#x %#x %#x", sense->flags,
375                       sense->add_sense_code, sense->add_sense_code_qual);
376         }
377
378         if (istate->orig_ca == 0) {
379                 tcmd_sense(ctio->init_id, NULL, SSD_KEY_NO_SENSE, 0, 0);
380                 warnx("REQUEST SENSE from %u but no pending CA!",
381                       ctio->init_id);
382         }
383
384         bcopy(sense, ctio->data_ptr, sizeof(struct scsi_sense_data));
385         dlen = offsetof(struct scsi_sense_data, extra_len) +
386                         sense->extra_len + 1;
387         ctio->dxfer_len = min(dlen, SCSI_CDB6_LEN(rsense->length));
388         ctio->ccb_h.flags |= CAM_DIR_IN | CAM_SEND_STATUS;
389         ctio->scsi_status = SCSI_STATUS_OK;
390         return (0);
391 }
392
393 static int
394 tcmd_rd_cap(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
395 {
396         struct scsi_read_capacity_data *srp;
397         struct atio_descr *a_descr;
398
399         a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
400         srp = (struct scsi_read_capacity_data *)ctio->data_ptr;
401
402         if (debug) {
403                 cdb_debug(a_descr->cdb, "READ CAP from %u (%u, %u): ",
404                           atio->init_id, volume_size - 1, sector_size);
405         }
406
407         bzero(srp, sizeof(*srp));
408         scsi_ulto4b(volume_size - 1, srp->addr);
409         scsi_ulto4b(sector_size, srp->length);
410
411         ctio->dxfer_len = sizeof(*srp);
412         ctio->ccb_h.flags |= CAM_DIR_IN | CAM_SEND_STATUS;
413         ctio->scsi_status = SCSI_STATUS_OK;
414         return (0);
415 }
416
417 static int
418 tcmd_rdwr(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
419 {
420         struct atio_descr *a_descr;
421         struct ctio_descr *c_descr;
422         int ret;
423
424         a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
425         c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr;
426
427         /* Command needs to be decoded */
428         if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_RESV) {
429                 if (debug)
430                         warnx("Calling rdwr_decode");
431                 ret = tcmd_rdwr_decode(atio, ctio);
432                 if (ret == 0) {
433                         send_ccb((union ccb *)ctio, /*priority*/1);
434                         return (0);
435                 }
436         }
437         ctio->ccb_h.flags |= a_descr->flags;
438
439         /* Call appropriate work function */
440         if ((a_descr->flags & CAM_DIR_IN) != 0) {
441                 ret = start_io(atio, ctio, CAM_DIR_IN);
442                 if (debug)
443                         warnx("Starting DIR_IN @%lld:%u", c_descr->offset,
444                               a_descr->targ_req);
445         } else {
446                 ret = start_io(atio, ctio, CAM_DIR_OUT);
447                 if (debug)
448                         warnx("Starting DIR_OUT @%lld:%u", c_descr->offset,
449                               a_descr->init_req);
450         }
451
452         return (ret);
453 }
454
455 static int
456 tcmd_rdwr_decode(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
457 {
458         u_int32_t blkno, count;
459         struct atio_descr *a_descr;
460         u_int8_t *cdb;
461
462         a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
463         cdb = a_descr->cdb;
464         if (debug)
465                 cdb_debug(cdb, "R/W from %u: ", atio->init_id);
466
467         if (cdb[0] == READ_6 || cdb[0] == WRITE_6) {
468                 struct scsi_rw_6 *rw_6 = (struct scsi_rw_6 *)cdb;
469                 blkno = scsi_3btoul(rw_6->addr);
470                 count = rw_6->length;
471         } else {
472                 struct scsi_rw_10 *rw_10 = (struct scsi_rw_10 *)cdb;
473                 blkno = scsi_4btoul(rw_10->addr);
474                 count = scsi_2btoul(rw_10->length);
475         }
476         if (blkno + count > volume_size) {
477                 warnx("Attempt to access past end of volume");
478                 tcmd_sense(ctio->init_id, ctio,
479                            SSD_KEY_ILLEGAL_REQUEST, 0x21, 0);
480                 return (0);
481         }
482
483         /* Get an (overall) data length and set direction */
484         a_descr->base_off = ((off_t)blkno) * sector_size;
485         a_descr->total_len = count * sector_size;
486         if (a_descr->total_len == 0) {
487                 if (debug)
488                         warnx("r/w 0 blocks @ blkno %u", blkno);
489                 tcmd_null_ok(atio, ctio);
490                 return (0);
491         } else if (cdb[0] == WRITE_6 || cdb[0] == WRITE_10) {
492                 a_descr->flags |= CAM_DIR_OUT;
493                 if (debug)
494                         warnx("write %u blocks @ blkno %u", count, blkno);
495         } else {
496                 a_descr->flags |= CAM_DIR_IN;
497                 if (debug)
498                         warnx("read %u blocks @ blkno %u", count, blkno);
499         }
500         return (1);
501 }
502
503 static int
504 start_io(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio, int dir)
505 {
506         struct atio_descr *a_descr;
507         struct ctio_descr *c_descr;
508         int ret;
509
510         /* Set up common structures */
511         a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
512         c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr;
513
514         if (dir == CAM_DIR_IN) {
515                 c_descr->offset = a_descr->base_off + a_descr->targ_req;
516                 ctio->dxfer_len = a_descr->total_len - a_descr->targ_req;
517         } else {
518                 c_descr->offset = a_descr->base_off + a_descr->init_req;
519                 ctio->dxfer_len = a_descr->total_len - a_descr->init_req;
520         }
521         ctio->dxfer_len = min(ctio->dxfer_len, buf_size);
522         assert(ctio->dxfer_len >= 0);
523
524         c_descr->aiocb.aio_offset = c_descr->offset;
525         c_descr->aiocb.aio_nbytes = ctio->dxfer_len;
526
527         /* If DIR_IN, start read from target, otherwise begin CTIO xfer. */
528         ret = 1;
529         if (dir == CAM_DIR_IN) {
530                 if (aio_read(&c_descr->aiocb) < 0)
531                         err(1, "aio_read"); /* XXX */
532                 a_descr->targ_req += ctio->dxfer_len;
533                 if (a_descr->targ_req == a_descr->total_len) {
534                         ctio->ccb_h.flags |= CAM_SEND_STATUS;
535                         ctio->scsi_status = SCSI_STATUS_OK;
536                         ret = 0;
537                 }
538         } else {
539                 if (a_descr->targ_ack == a_descr->total_len)
540                         tcmd_null_ok(atio, ctio);
541                 a_descr->init_req += ctio->dxfer_len;
542                 if (a_descr->init_req == a_descr->total_len &&
543                     ctio->dxfer_len > 0) {
544                         /*
545                          * If data phase done, remove atio from workq.
546                          * The completion handler will call work_atio to
547                          * send the final status.
548                          */
549                         ret = 0;
550                 }
551                 send_ccb((union ccb *)ctio, /*priority*/1);
552         }
553
554         return (ret);
555 }
556
557 static void
558 tcmd_rdwr_done(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio,
559                io_ops event)
560 {
561         struct atio_descr *a_descr;
562         struct ctio_descr *c_descr;
563
564         a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
565         c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr;
566
567         switch (event) {
568         case AIO_DONE:
569                 if (aio_return(&c_descr->aiocb) < 0) {
570                         warn("aio_return error");
571                         /* XXX */
572                         tcmd_sense(ctio->init_id, ctio,
573                                    SSD_KEY_MEDIUM_ERROR, 0, 0);
574                         send_ccb((union ccb *)ctio, /*priority*/1);
575                         break;
576                 }
577                 a_descr->targ_ack += ctio->dxfer_len;
578                 if ((a_descr->flags & CAM_DIR_IN) != 0) {
579                         if (debug)
580                                 warnx("sending CTIO for AIO read");
581                         a_descr->init_req += ctio->dxfer_len;
582                         send_ccb((union ccb *)ctio, /*priority*/1);
583                 } else {
584                         /* Use work function to send final status */
585                         if (a_descr->init_req == a_descr->total_len)
586                                 work_atio(atio);
587                         if (debug)
588                                 warnx("AIO done freeing CTIO");
589                         free_ccb((union ccb *)ctio);
590                 }
591                 break;
592         case CTIO_DONE:
593                 if (ctio->ccb_h.status != CAM_REQ_CMP) {
594                         /* XXX */
595                         errx(1, "CTIO failed, status %#x", ctio->ccb_h.status);
596                 }
597                 a_descr->init_ack += ctio->dxfer_len;
598                 if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_OUT &&
599                     ctio->dxfer_len > 0) {
600                         if (debug)
601                                 warnx("sending AIO for CTIO write");
602                         a_descr->targ_req += ctio->dxfer_len;
603                         if (aio_write(&c_descr->aiocb) < 0)
604                                 err(1, "aio_write"); /* XXX */
605                 } else {
606                         if (debug)
607                                 warnx("CTIO done freeing CTIO");
608                         free_ccb((union ccb *)ctio);
609                 }
610                 break;
611         default:
612                 warnx("Unknown completion code %d", event);
613                 abort();
614                 /* NOTREACHED */
615         }
616 }
617
618 /* Simple ok message used by TUR, SYNC_CACHE, etc. */
619 static int
620 tcmd_null_ok(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
621 {
622         if (debug) {
623                 struct atio_descr *a_descr;
624
625                 a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
626                 cdb_debug(a_descr->cdb, "Sending null ok to %u : ", atio->init_id);
627         }
628
629         ctio->dxfer_len = 0;
630         ctio->ccb_h.flags &= ~CAM_DIR_MASK;
631         ctio->ccb_h.flags |= CAM_DIR_NONE | CAM_SEND_STATUS;
632         ctio->scsi_status = SCSI_STATUS_OK;
633         return (0);
634 }
635
636 /* Simple illegal request message used by MODE SENSE, etc. */
637 static int
638 tcmd_illegal_req(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
639 {
640         if (debug) {
641                 struct atio_descr *a_descr;
642
643                 a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
644                 cdb_debug(a_descr->cdb, "Sending ill req to %u: ", atio->init_id);
645         }
646         
647         tcmd_sense(atio->init_id, ctio, SSD_KEY_ILLEGAL_REQUEST,
648                    /*asc*/0x24, /*ascq*/0);
649         return (0);
650 }
651
652 static void
653 cdb_debug(u_int8_t *cdb, const char *msg, ...)
654 {
655         char msg_buf[512];
656         int len;
657         va_list ap;
658
659         va_start(ap, msg);
660         vsnprintf(msg_buf, sizeof(msg_buf), msg, ap);
661         va_end(ap);
662         len = strlen(msg_buf);
663         scsi_cdb_string(cdb, msg_buf + len, sizeof(msg_buf) - len);
664         warnx("%s", msg_buf);
665 }