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