xref: /freebsd/share/examples/scsi_target/scsi_cmds.c (revision d056fa046c6a91b90cd98165face0e42a33a5173)
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$
29  */
30 
31 #include <stdio.h>
32 #include <stddef.h>
33 #include <stdarg.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <err.h>
37 #include <aio.h>
38 #include <assert.h>
39 #include <sys/param.h>
40 #include <sys/types.h>
41 
42 #include <cam/cam.h>
43 #include <cam/cam_ccb.h>
44 #include <cam/scsi/scsi_all.h>
45 #include <cam/scsi/scsi_targetio.h>
46 #include "scsi_target.h"
47 
48 typedef int targ_start_func(struct ccb_accept_tio *, struct ccb_scsiio *);
49 typedef void targ_done_func(struct ccb_accept_tio *, struct ccb_scsiio *,
50 			      io_ops);
51 #ifndef	REPORT_LUNS
52 #define	REPORT_LUNS	0xa0
53 #endif
54 
55 struct targ_cdb_handlers {
56 	u_int8_t	  cmd;
57 	targ_start_func  *start;
58 	targ_done_func	 *done;
59 #define ILLEGAL_CDB	  0xFF
60 };
61 
62 static targ_start_func		tcmd_inquiry;
63 static targ_start_func		tcmd_req_sense;
64 static targ_start_func		tcmd_rd_cap;
65 #ifdef READ_16
66 static targ_start_func		tcmd_rd_cap16;
67 #endif
68 static targ_start_func		tcmd_rdwr;
69 static targ_start_func		tcmd_rdwr_decode;
70 static targ_done_func		tcmd_rdwr_done;
71 static targ_start_func		tcmd_null_ok;
72 static targ_start_func		tcmd_illegal_req;
73 static int			start_io(struct ccb_accept_tio *atio,
74 					 struct ccb_scsiio *ctio, int dir);
75 static int init_inquiry(u_int16_t req_flags, u_int16_t sim_flags);
76 static struct initiator_state *
77 			tcmd_get_istate(u_int init_id);
78 static void cdb_debug(u_int8_t *cdb, const char *msg, ...);
79 
80 static struct targ_cdb_handlers cdb_handlers[] = {
81 	{ READ_10,		tcmd_rdwr,		tcmd_rdwr_done },
82 	{ WRITE_10,		tcmd_rdwr,		tcmd_rdwr_done },
83 	{ READ_6,		tcmd_rdwr,		tcmd_rdwr_done },
84 	{ WRITE_6,		tcmd_rdwr,		tcmd_rdwr_done },
85 	{ INQUIRY,		tcmd_inquiry,		NULL },
86 	{ REQUEST_SENSE,	tcmd_req_sense,		NULL },
87 	{ READ_CAPACITY,	tcmd_rd_cap,		NULL },
88 	{ TEST_UNIT_READY,	tcmd_null_ok,		NULL },
89 	{ START_STOP_UNIT,	tcmd_null_ok,		NULL },
90 	{ SYNCHRONIZE_CACHE,	tcmd_null_ok,		NULL },
91 	{ MODE_SENSE_6,		tcmd_illegal_req,	NULL },
92 	{ MODE_SELECT_6,	tcmd_illegal_req,	NULL },
93 	{ REPORT_LUNS,		tcmd_illegal_req,	NULL },
94 #ifdef READ_16
95 	{ READ_16,		tcmd_rdwr,		tcmd_rdwr_done },
96 	{ WRITE_16,		tcmd_rdwr,		tcmd_rdwr_done },
97 	{ SERVICE_ACTION_IN,	tcmd_rd_cap16,		NULL },
98 #endif
99 	{ ILLEGAL_CDB,		NULL,			NULL }
100 };
101 
102 static struct scsi_inquiry_data inq_data;
103 static struct initiator_state istates[MAX_INITIATORS];
104 extern int		debug;
105 extern uint64_t		volume_size;
106 extern size_t		sector_size;
107 extern size_t		buf_size;
108 
109 cam_status
110 tcmd_init(u_int16_t req_inq_flags, u_int16_t sim_inq_flags)
111 {
112 	struct initiator_state *istate;
113 	int i, ret;
114 
115 	/* Initialize our inquiry data */
116 	ret = init_inquiry(req_inq_flags, sim_inq_flags);
117 	if (ret != 0)
118         	return (ret);
119 
120 	/* We start out life with a UA to indicate power-on/reset. */
121 	for (i = 0; i < MAX_INITIATORS; i++) {
122 		istate = tcmd_get_istate(i);
123 		bzero(istate, sizeof(*istate));
124 		istate->pending_ua = UA_POWER_ON;
125 	}
126 
127 	return (0);
128 }
129 
130 /* Caller allocates CTIO, sets its init_id
131 return 0 if done, 1 if more processing needed
132 on 0, caller sets SEND_STATUS */
133 int
134 tcmd_handle(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio, io_ops event)
135 {
136 	static struct targ_cdb_handlers *last_cmd;
137 	struct initiator_state *istate;
138 	struct atio_descr *a_descr;
139 	int ret;
140 
141 	if (debug) {
142 		warnx("tcmd_handle atio %p ctio %p atioflags %#x", atio, ctio,
143 		      atio->ccb_h.flags);
144 	}
145 	ret = 0;
146 	a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
147 
148 	/* Do a full lookup if one-behind cache failed */
149 	if (last_cmd == NULL || last_cmd->cmd != a_descr->cdb[0]) {
150 		struct targ_cdb_handlers *h;
151 
152 		for (h = cdb_handlers; h->cmd != ILLEGAL_CDB; h++) {
153 			if (a_descr->cdb[0] == h->cmd)
154 				break;
155 		}
156 		last_cmd = h;
157 	}
158 
159 	/* call completion and exit */
160 	if (event != ATIO_WORK) {
161 		if (last_cmd->done != NULL)
162 			last_cmd->done(atio, ctio, event);
163 		else
164 			free_ccb((union ccb *)ctio);
165 		return (1);
166 	}
167 
168 	if (last_cmd->cmd == ILLEGAL_CDB) {
169 		if (event != ATIO_WORK) {
170 			warnx("no done func for %#x???", a_descr->cdb[0]);
171 			abort();
172 		}
173 		/* Not found, return illegal request */
174 		warnx("cdb %#x not handled", a_descr->cdb[0]);
175 		tcmd_illegal_req(atio, ctio);
176 		send_ccb((union ccb *)ctio, /*priority*/1);
177 		return (0);
178 	}
179 
180 	istate = tcmd_get_istate(ctio->init_id);
181 	if (istate == NULL) {
182 		tcmd_illegal_req(atio, ctio);
183 		send_ccb((union ccb *)ctio, /*priority*/1);
184 		return (0);
185 	}
186 
187 	if (istate->pending_ca == 0 && istate->pending_ua != 0 &&
188 	    a_descr->cdb[0] != INQUIRY) {
189 		tcmd_sense(ctio->init_id, ctio, SSD_KEY_UNIT_ATTENTION,
190 			   0x29, istate->pending_ua == UA_POWER_ON ? 1 : 2);
191 		istate->pending_ca = CA_UNIT_ATTN;
192 		if (debug) {
193 			cdb_debug(a_descr->cdb, "UA active for %u: ",
194 				  atio->init_id);
195 		}
196 		send_ccb((union ccb *)ctio, /*priority*/1);
197 		return (0);
198 	}
199 
200 	/* Store current CA and UA for later */
201 	istate->orig_ua = istate->pending_ua;
202 	istate->orig_ca = istate->pending_ca;
203 
204 	/*
205 	 * As per SAM2, any command that occurs
206 	 * after a CA is reported, clears the CA.  We must
207 	 * also clear the UA condition, if any, that caused
208 	 * the CA to occur assuming the UA is not for a
209 	 * persistent condition.
210 	 */
211 	istate->pending_ca = CA_NONE;
212 	if (istate->orig_ca == CA_UNIT_ATTN)
213 		istate->pending_ua = UA_NONE;
214 
215 	/* If we have a valid handler, call start or completion function */
216 	if (last_cmd->cmd != ILLEGAL_CDB) {
217 		ret = last_cmd->start(atio, ctio);
218 		/* XXX hack */
219 		if (last_cmd->start != tcmd_rdwr) {
220 			a_descr->init_req += ctio->dxfer_len;
221 			send_ccb((union ccb *)ctio, /*priority*/1);
222 		}
223 	}
224 
225 	return (ret);
226 }
227 
228 static struct initiator_state *
229 tcmd_get_istate(u_int init_id)
230 {
231 	if (init_id >= MAX_INITIATORS) {
232 		warnx("illegal init_id %d, max %d", init_id, MAX_INITIATORS - 1);
233 		return (NULL);
234 	} else {
235 		return (&istates[init_id]);
236 	}
237 }
238 
239 void
240 tcmd_sense(u_int init_id, struct ccb_scsiio *ctio, u_int8_t flags,
241 	       u_int8_t asc, u_int8_t ascq)
242 {
243 	struct initiator_state *istate;
244 	struct scsi_sense_data *sense;
245 
246 	/* Set our initiator's istate */
247 	istate = tcmd_get_istate(init_id);
248 	if (istate == NULL)
249 		return;
250 	istate->pending_ca |= CA_CMD_SENSE; /* XXX set instead of or? */
251 	sense = &istate->sense_data;
252 	bzero(sense, sizeof(*sense));
253 	sense->error_code = SSD_CURRENT_ERROR;
254 	sense->flags = flags;
255 	sense->add_sense_code = asc;
256 	sense->add_sense_code_qual = ascq;
257 	sense->extra_len =
258 		offsetof(struct scsi_sense_data, sense_key_spec[2]) -
259 		offsetof(struct scsi_sense_data, extra_len);
260 
261 	/* Fill out the supplied CTIO */
262 	if (ctio != NULL) {
263 		bcopy(sense, &ctio->sense_data, sizeof(*sense));
264 		ctio->sense_len = sizeof(*sense);  /* XXX */
265 		ctio->ccb_h.flags &= ~CAM_DIR_MASK;
266 		ctio->ccb_h.flags |= CAM_DIR_NONE | CAM_SEND_SENSE |
267 				     CAM_SEND_STATUS;
268 		ctio->dxfer_len = 0;
269 		ctio->scsi_status = SCSI_STATUS_CHECK_COND;
270 	}
271 }
272 
273 void
274 tcmd_ua(u_int init_id, ua_types new_ua)
275 {
276 	struct initiator_state *istate;
277 	u_int start, end;
278 
279 	if (init_id == CAM_TARGET_WILDCARD) {
280 		start = 0;
281 		end = MAX_INITIATORS - 1;
282 	} else {
283 		start = end = init_id;
284 	}
285 
286 	for (; start <= end; start++) {
287 		istate = tcmd_get_istate(start);
288 		if (istate == NULL)
289 			break;
290 		istate->pending_ua = new_ua;
291 	}
292 }
293 
294 static int
295 tcmd_inquiry(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
296 {
297 	struct scsi_inquiry *inq;
298 	struct atio_descr *a_descr;
299 	struct initiator_state *istate;
300 	struct scsi_sense_data *sense;
301 
302 	a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
303 	inq = (struct scsi_inquiry *)a_descr->cdb;
304 
305 	if (debug)
306 		cdb_debug(a_descr->cdb, "INQUIRY from %u: ", atio->init_id);
307 	/*
308 	 * Validate the command.  We don't support any VPD pages, so
309 	 * complain if EVPD or CMDDT is set.
310 	 */
311 	istate = tcmd_get_istate(ctio->init_id);
312 	sense = &istate->sense_data;
313 	if ((inq->byte2 & SI_EVPD) != 0) {
314 		tcmd_illegal_req(atio, ctio);
315 		sense->sense_key_spec[0] = SSD_SCS_VALID | SSD_FIELDPTR_CMD |
316 			SSD_BITPTR_VALID | /*bit value*/1;
317 		sense->sense_key_spec[1] = 0;
318 		sense->sense_key_spec[2] =
319 			offsetof(struct scsi_inquiry, byte2);
320 	} else if (inq->page_code != 0) {
321 		tcmd_illegal_req(atio, ctio);
322 		sense->sense_key_spec[0] = SSD_SCS_VALID | SSD_FIELDPTR_CMD;
323 		sense->sense_key_spec[1] = 0;
324 		sense->sense_key_spec[2] =
325 			offsetof(struct scsi_inquiry, page_code);
326 	} else {
327 		bcopy(&inq_data, ctio->data_ptr, sizeof(inq_data));
328 		ctio->dxfer_len = inq_data.additional_length + 4;
329 		ctio->dxfer_len = min(ctio->dxfer_len,
330 				      SCSI_CDB6_LEN(inq->length));
331 		ctio->ccb_h.flags |= CAM_DIR_IN | CAM_SEND_STATUS;
332 		ctio->scsi_status = SCSI_STATUS_OK;
333 	}
334 	return (0);
335 }
336 
337 /* Initialize the inquiry response structure with the requested flags */
338 static int
339 init_inquiry(u_int16_t req_flags, u_int16_t sim_flags)
340 {
341 	struct scsi_inquiry_data *inq;
342 
343 	inq = &inq_data;
344 	bzero(inq, sizeof(*inq));
345 	inq->device = T_DIRECT | (SID_QUAL_LU_CONNECTED << 5);
346 #ifdef SCSI_REV_SPC
347 	inq->version = SCSI_REV_SPC; /* was 2 */
348 #else
349 	inq->version = SCSI_REV_3; /* was 2 */
350 #endif
351 
352 	/*
353 	 * XXX cpi.hba_inquiry doesn't support Addr16 so we give the
354 	 * user what they want if they ask for it.
355 	 */
356 	if ((req_flags & SID_Addr16) != 0) {
357 		sim_flags |= SID_Addr16;
358 		warnx("Not sure SIM supports Addr16 but enabling it anyway");
359 	}
360 
361 	/* Advertise only what the SIM can actually support */
362 	req_flags &= sim_flags;
363 	scsi_ulto2b(req_flags, &inq->reserved[1]);
364 
365 	inq->response_format = 2; /* SCSI2 Inquiry Format */
366 	inq->additional_length = SHORT_INQUIRY_LENGTH -
367 		offsetof(struct scsi_inquiry_data, additional_length);
368 	bcopy("FreeBSD ", inq->vendor, SID_VENDOR_SIZE);
369 	bcopy("Emulated Disk   ", inq->product, SID_PRODUCT_SIZE);
370 	bcopy("0.1 ", inq->revision, SID_REVISION_SIZE);
371 	return (0);
372 }
373 
374 static int
375 tcmd_req_sense(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
376 {
377 	struct scsi_request_sense *rsense;
378 	struct scsi_sense_data *sense;
379 	struct initiator_state *istate;
380 	size_t dlen;
381 	struct atio_descr *a_descr;
382 
383 	a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
384 	rsense = (struct scsi_request_sense *)a_descr->cdb;
385 
386 	istate = tcmd_get_istate(ctio->init_id);
387 	sense = &istate->sense_data;
388 
389 	if (debug) {
390 		cdb_debug(a_descr->cdb, "REQ SENSE from %u: ", atio->init_id);
391 		warnx("Sending sense: %#x %#x %#x", sense->flags,
392 		      sense->add_sense_code, sense->add_sense_code_qual);
393 	}
394 
395 	if (istate->orig_ca == 0) {
396 		tcmd_sense(ctio->init_id, NULL, SSD_KEY_NO_SENSE, 0, 0);
397 		warnx("REQUEST SENSE from %u but no pending CA!",
398 		      ctio->init_id);
399 	}
400 
401 	bcopy(sense, ctio->data_ptr, sizeof(struct scsi_sense_data));
402 	dlen = offsetof(struct scsi_sense_data, extra_len) +
403 			sense->extra_len + 1;
404 	ctio->dxfer_len = min(dlen, SCSI_CDB6_LEN(rsense->length));
405 	ctio->ccb_h.flags |= CAM_DIR_IN | CAM_SEND_STATUS;
406 	ctio->scsi_status = SCSI_STATUS_OK;
407 	return (0);
408 }
409 
410 static int
411 tcmd_rd_cap(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
412 {
413 	struct scsi_read_capacity_data *srp;
414 	struct atio_descr *a_descr;
415 	uint32_t vsize;
416 
417 	a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
418 	srp = (struct scsi_read_capacity_data *)ctio->data_ptr;
419 
420 	if (volume_size > 0xffffffff)
421 		vsize = 0xffffffff;
422 	else
423 		vsize = (uint32_t)(volume_size - 1);
424 
425 	if (debug) {
426 		cdb_debug(a_descr->cdb, "READ CAP from %u (%u, %u): ",
427 			  atio->init_id, vsize, sector_size);
428 	}
429 
430 	bzero(srp, sizeof(*srp));
431 	scsi_ulto4b(vsize, srp->addr);
432 	scsi_ulto4b(sector_size, srp->length);
433 
434 	ctio->dxfer_len = sizeof(*srp);
435 	ctio->ccb_h.flags |= CAM_DIR_IN | CAM_SEND_STATUS;
436 	ctio->scsi_status = SCSI_STATUS_OK;
437 	return (0);
438 }
439 
440 #ifdef READ_16
441 static int
442 tcmd_rd_cap16(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
443 {
444 	struct scsi_read_capacity_16 *scsi_cmd;
445 	struct scsi_read_capacity_data_long *srp;
446 	struct atio_descr *a_descr;
447 
448 	a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
449 	scsi_cmd = (struct scsi_read_capacity_16 *)a_descr->cdb;
450 	srp = (struct scsi_read_capacity_data_long *)ctio->data_ptr;
451 
452 	if (scsi_cmd->service_action != SRC16_SERVICE_ACTION) {
453 		tcmd_illegal_req(atio, ctio);
454 		return (0);
455 	}
456 
457 	if (debug) {
458 		cdb_debug(a_descr->cdb, "READ CAP16 from %u (%u, %u): ",
459 			  atio->init_id, volume_size - 1, sector_size);
460 	}
461 
462 	bzero(srp, sizeof(*srp));
463 	scsi_u64to8b(volume_size - 1, srp->addr);
464 	scsi_ulto4b(sector_size, srp->length);
465 
466 	ctio->dxfer_len = sizeof(*srp);
467 	ctio->ccb_h.flags |= CAM_DIR_IN | CAM_SEND_STATUS;
468 	ctio->scsi_status = SCSI_STATUS_OK;
469 	return (0);
470 }
471 #endif
472 
473 static int
474 tcmd_rdwr(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
475 {
476 	struct atio_descr *a_descr;
477 	struct ctio_descr *c_descr;
478 	int ret;
479 
480 	a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
481 	c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr;
482 
483 	/* Command needs to be decoded */
484 	if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_RESV) {
485 		if (debug)
486 			warnx("Calling rdwr_decode");
487 		ret = tcmd_rdwr_decode(atio, ctio);
488 		if (ret == 0) {
489 			send_ccb((union ccb *)ctio, /*priority*/1);
490 			return (0);
491 		}
492 	}
493 	ctio->ccb_h.flags |= a_descr->flags;
494 
495 	/* Call appropriate work function */
496 	if ((a_descr->flags & CAM_DIR_IN) != 0) {
497 		ret = start_io(atio, ctio, CAM_DIR_IN);
498 		if (debug)
499 #if __FreeBSD_version >= 500000
500 			warnx("Starting DIR_IN @%jd:%u",
501 #else
502 			warnx("Starting DIR_IN @%lld:%u",
503 #endif
504 			    c_descr->offset, a_descr->targ_req);
505 	} else {
506 		ret = start_io(atio, ctio, CAM_DIR_OUT);
507 		if (debug)
508 #if __FreeBSD_version >= 500000
509 			warnx("Starting DIR_OUT @%jd:%u",
510 #else
511 			warnx("Starting DIR_OUT @%lld:%u",
512 #endif
513 			    c_descr->offset, a_descr->init_req);
514 	}
515 
516 	return (ret);
517 }
518 
519 static int
520 tcmd_rdwr_decode(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
521 {
522 	uint64_t blkno;
523 	uint32_t count;
524 	struct atio_descr *a_descr;
525 	u_int8_t *cdb;
526 
527 	a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
528 	cdb = a_descr->cdb;
529 	if (debug)
530 		cdb_debug(cdb, "R/W from %u: ", atio->init_id);
531 
532 	switch (cdb[0]) {
533 	case READ_6:
534 	case WRITE_6:
535 	{
536 		struct scsi_rw_6 *rw_6 = (struct scsi_rw_6 *)cdb;
537 		blkno = scsi_3btoul(rw_6->addr);
538 		count = rw_6->length;
539 		break;
540 	}
541 	case READ_10:
542 	case WRITE_10:
543 	{
544 		struct scsi_rw_10 *rw_10 = (struct scsi_rw_10 *)cdb;
545 		blkno = scsi_4btoul(rw_10->addr);
546 		count = scsi_2btoul(rw_10->length);
547 		break;
548 	}
549 #ifdef READ_16
550 	case READ_16:
551 	case WRITE_16:
552 	{
553 		struct scsi_rw_16 *rw_16 = (struct scsi_rw_16 *)cdb;
554 		blkno = scsi_8btou64(rw_16->addr);
555 		count = scsi_4btoul(rw_16->length);
556 		break;
557 	}
558 #endif
559 	default:
560 		tcmd_illegal_req(atio, ctio);
561 		return (0);
562 	}
563 	if (blkno + count > volume_size) {
564 		warnx("Attempt to access past end of volume");
565 		tcmd_sense(ctio->init_id, ctio,
566 			   SSD_KEY_ILLEGAL_REQUEST, 0x21, 0);
567 		return (0);
568 	}
569 
570 	/* Get an (overall) data length and set direction */
571 	a_descr->base_off = ((off_t)blkno) * sector_size;
572 	a_descr->total_len = count * sector_size;
573 	if (a_descr->total_len == 0) {
574 		if (debug)
575 #if __FreeBSD_version >= 500000
576 			warnx("r/w 0 blocks @ blkno %ju", blkno);
577 #else
578 			warnx("r/w 0 blocks @ blkno %llu", blkno);
579 #endif
580 		tcmd_null_ok(atio, ctio);
581 		return (0);
582 	} else if (cdb[0] == WRITE_6 || cdb[0] == WRITE_10) {
583 		a_descr->flags |= CAM_DIR_OUT;
584 		if (debug)
585 #if __FreeBSD_version >= 500000
586 			warnx("write %u blocks @ blkno %ju", count, blkno);
587 #else
588 			warnx("write %u blocks @ blkno %llu", count, blkno);
589 #endif
590 	} else {
591 		a_descr->flags |= CAM_DIR_IN;
592 		if (debug)
593 #if __FreeBSD_version >= 500000
594 			warnx("read %u blocks @ blkno %ju", count, blkno);
595 #else
596 			warnx("read %u blocks @ blkno %llu", count, blkno);
597 #endif
598 	}
599 	return (1);
600 }
601 
602 static int
603 start_io(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio, int dir)
604 {
605 	struct atio_descr *a_descr;
606 	struct ctio_descr *c_descr;
607 	int ret;
608 
609 	/* Set up common structures */
610 	a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
611 	c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr;
612 
613 	if (dir == CAM_DIR_IN) {
614 		c_descr->offset = a_descr->base_off + a_descr->targ_req;
615 		ctio->dxfer_len = a_descr->total_len - a_descr->targ_req;
616 	} else {
617 		c_descr->offset = a_descr->base_off + a_descr->init_req;
618 		ctio->dxfer_len = a_descr->total_len - a_descr->init_req;
619 	}
620 	ctio->dxfer_len = min(ctio->dxfer_len, buf_size);
621 	assert(ctio->dxfer_len >= 0);
622 
623 	c_descr->aiocb.aio_offset = c_descr->offset;
624 	c_descr->aiocb.aio_nbytes = ctio->dxfer_len;
625 
626 	/* If DIR_IN, start read from target, otherwise begin CTIO xfer. */
627 	ret = 1;
628 	if (dir == CAM_DIR_IN) {
629 		if (aio_read(&c_descr->aiocb) < 0)
630 			err(1, "aio_read"); /* XXX */
631 		a_descr->targ_req += ctio->dxfer_len;
632 		if (a_descr->targ_req == a_descr->total_len) {
633 			ctio->ccb_h.flags |= CAM_SEND_STATUS;
634 			ctio->scsi_status = SCSI_STATUS_OK;
635 			ret = 0;
636 		}
637 	} else {
638 		if (a_descr->targ_ack == a_descr->total_len)
639 			tcmd_null_ok(atio, ctio);
640 		a_descr->init_req += ctio->dxfer_len;
641 		if (a_descr->init_req == a_descr->total_len &&
642 		    ctio->dxfer_len > 0) {
643 			/*
644 			 * If data phase done, remove atio from workq.
645 			 * The completion handler will call work_atio to
646 			 * send the final status.
647 			 */
648 			ret = 0;
649 		}
650 		send_ccb((union ccb *)ctio, /*priority*/1);
651 	}
652 
653 	return (ret);
654 }
655 
656 static void
657 tcmd_rdwr_done(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio,
658 	       io_ops event)
659 {
660 	struct atio_descr *a_descr;
661 	struct ctio_descr *c_descr;
662 
663 	a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
664 	c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr;
665 
666 	switch (event) {
667 	case AIO_DONE:
668 		if (aio_return(&c_descr->aiocb) < 0) {
669 			warn("aio_return error");
670 			/* XXX */
671 			tcmd_sense(ctio->init_id, ctio,
672 				   SSD_KEY_MEDIUM_ERROR, 0, 0);
673 			send_ccb((union ccb *)ctio, /*priority*/1);
674 			break;
675 		}
676 		a_descr->targ_ack += ctio->dxfer_len;
677 		if ((a_descr->flags & CAM_DIR_IN) != 0) {
678 			if (debug)
679 				warnx("sending CTIO for AIO read");
680 			a_descr->init_req += ctio->dxfer_len;
681 			send_ccb((union ccb *)ctio, /*priority*/1);
682 		} else {
683 			/* Use work function to send final status */
684 			if (a_descr->init_req == a_descr->total_len)
685 				work_atio(atio);
686 			if (debug)
687 				warnx("AIO done freeing CTIO");
688 			free_ccb((union ccb *)ctio);
689 		}
690 		break;
691 	case CTIO_DONE:
692 		switch (ctio->ccb_h.status & CAM_STATUS_MASK) {
693 		case CAM_REQ_CMP:
694 			break;
695 		case CAM_REQUEUE_REQ:
696 			warnx("requeueing request");
697 			if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_OUT) {
698 				if (aio_write(&c_descr->aiocb) < 0) {
699 					err(1, "aio_write"); /* XXX */
700 				}
701 			} else {
702 				if (aio_read(&c_descr->aiocb) < 0) {
703 					err(1, "aio_read"); /* XXX */
704 				}
705 			}
706 			return;
707 		default:
708 			errx(1, "CTIO failed, status %#x", ctio->ccb_h.status);
709 		}
710 		a_descr->init_ack += ctio->dxfer_len;
711 		if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_OUT &&
712 		    ctio->dxfer_len > 0) {
713 			if (debug)
714 				warnx("sending AIO for CTIO write");
715 			a_descr->targ_req += ctio->dxfer_len;
716 			if (aio_write(&c_descr->aiocb) < 0)
717 				err(1, "aio_write"); /* XXX */
718 		} else {
719 			if (debug)
720 				warnx("CTIO done freeing CTIO");
721 			free_ccb((union ccb *)ctio);
722 		}
723 		break;
724 	default:
725 		warnx("Unknown completion code %d", event);
726 		abort();
727 		/* NOTREACHED */
728 	}
729 }
730 
731 /* Simple ok message used by TUR, SYNC_CACHE, etc. */
732 static int
733 tcmd_null_ok(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
734 {
735 	if (debug) {
736 		struct atio_descr *a_descr;
737 
738 		a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
739 		cdb_debug(a_descr->cdb, "Sending null ok to %u : ", atio->init_id);
740 	}
741 
742 	ctio->dxfer_len = 0;
743 	ctio->ccb_h.flags &= ~CAM_DIR_MASK;
744 	ctio->ccb_h.flags |= CAM_DIR_NONE | CAM_SEND_STATUS;
745 	ctio->scsi_status = SCSI_STATUS_OK;
746 	return (0);
747 }
748 
749 /* Simple illegal request message used by MODE SENSE, etc. */
750 static int
751 tcmd_illegal_req(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
752 {
753 	if (debug) {
754 		struct atio_descr *a_descr;
755 
756 		a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
757 		cdb_debug(a_descr->cdb, "Sending ill req to %u: ", atio->init_id);
758 	}
759 
760 	tcmd_sense(atio->init_id, ctio, SSD_KEY_ILLEGAL_REQUEST,
761 		   /*asc*/0x24, /*ascq*/0);
762 	return (0);
763 }
764 
765 static void
766 cdb_debug(u_int8_t *cdb, const char *msg, ...)
767 {
768 	char msg_buf[512];
769 	int len;
770 	va_list ap;
771 
772 	va_start(ap, msg);
773 	vsnprintf(msg_buf, sizeof(msg_buf), msg, ap);
774 	va_end(ap);
775 	len = strlen(msg_buf);
776 	scsi_cdb_string(cdb, msg_buf + len, sizeof(msg_buf) - len);
777 	warnx("%s", msg_buf);
778 }
779