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