xref: /freebsd/sys/cam/scsi/scsi_sg.c (revision 2e3507c25e42292b45a5482e116d278f5515d04d)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2007 Scott Long
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 
29 /*
30  * scsi_sg peripheral driver.  This driver is meant to implement the Linux
31  * SG passthrough interface for SCSI.
32  */
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/types.h>
38 #include <sys/bio.h>
39 #include <sys/malloc.h>
40 #include <sys/fcntl.h>
41 #include <sys/ioccom.h>
42 #include <sys/conf.h>
43 #include <sys/errno.h>
44 #include <sys/devicestat.h>
45 #include <sys/proc.h>
46 #include <sys/uio.h>
47 
48 #include <cam/cam.h>
49 #include <cam/cam_ccb.h>
50 #include <cam/cam_periph.h>
51 #include <cam/cam_queue.h>
52 #include <cam/cam_xpt_periph.h>
53 #include <cam/cam_debug.h>
54 #include <cam/cam_sim.h>
55 
56 #include <cam/scsi/scsi_all.h>
57 #include <cam/scsi/scsi_message.h>
58 #include <cam/scsi/scsi_sg.h>
59 
60 typedef enum {
61 	SG_FLAG_LOCKED		= 0x01,
62 	SG_FLAG_INVALID		= 0x02
63 } sg_flags;
64 
65 typedef enum {
66 	SG_STATE_NORMAL
67 } sg_state;
68 
69 typedef enum {
70 	SG_RDWR_FREE,
71 	SG_RDWR_INPROG,
72 	SG_RDWR_DONE
73 } sg_rdwr_state;
74 
75 typedef enum {
76 	SG_CCB_RDWR_IO
77 } sg_ccb_types;
78 
79 #define ccb_type	ppriv_field0
80 #define ccb_rdwr	ppriv_ptr1
81 
82 struct sg_rdwr {
83 	TAILQ_ENTRY(sg_rdwr)	rdwr_link;
84 	int			tag;
85 	int			state;
86 	int			buf_len;
87 	char			*buf;
88 	union ccb		*ccb;
89 	union {
90 		struct sg_header hdr;
91 		struct sg_io_hdr io_hdr;
92 	} hdr;
93 };
94 
95 struct sg_softc {
96 	sg_state		state;
97 	sg_flags		flags;
98 	int			open_count;
99 	u_int			maxio;
100 	struct devstat		*device_stats;
101 	TAILQ_HEAD(, sg_rdwr)	rdwr_done;
102 	struct cdev		*dev;
103 	int			sg_timeout;
104 	int			sg_user_timeout;
105 	uint8_t			pd_type;
106 };
107 
108 static d_open_t		sgopen;
109 static d_close_t	sgclose;
110 static d_ioctl_t	sgioctl;
111 static d_write_t	sgwrite;
112 static d_read_t		sgread;
113 
114 static periph_init_t	sginit;
115 static periph_ctor_t	sgregister;
116 static periph_oninv_t	sgoninvalidate;
117 static periph_dtor_t	sgcleanup;
118 static void		sgasync(void *callback_arg, uint32_t code,
119 				struct cam_path *path, void *arg);
120 static void		sgdone(struct cam_periph *periph, union ccb *done_ccb);
121 static int		sgsendccb(struct cam_periph *periph, union ccb *ccb);
122 static int		sgsendrdwr(struct cam_periph *periph, union ccb *ccb);
123 static int		sgerror(union ccb *ccb, uint32_t cam_flags,
124 				uint32_t sense_flags);
125 static void		sg_scsiio_status(struct ccb_scsiio *csio,
126 					 u_short *hoststat, u_short *drvstat);
127 
128 static int		scsi_group_len(u_char cmd);
129 
130 static struct periph_driver sgdriver =
131 {
132 	sginit, "sg",
133 	TAILQ_HEAD_INITIALIZER(sgdriver.units), /* gen */ 0
134 };
135 PERIPHDRIVER_DECLARE(sg, sgdriver);
136 
137 static struct cdevsw sg_cdevsw = {
138 	.d_version =	D_VERSION,
139 	.d_flags =	D_TRACKCLOSE,
140 	.d_open =	sgopen,
141 	.d_close =	sgclose,
142 	.d_ioctl =	sgioctl,
143 	.d_write =	sgwrite,
144 	.d_read =	sgread,
145 	.d_name =	"sg",
146 };
147 
148 static int sg_version = 30125;
149 
150 static void
151 sginit(void)
152 {
153 	cam_status status;
154 
155 	/*
156 	 * Install a global async callback.  This callback will receive aync
157 	 * callbacks like "new device found".
158 	 */
159 	status = xpt_register_async(AC_FOUND_DEVICE, sgasync, NULL, NULL);
160 
161 	if (status != CAM_REQ_CMP) {
162 		printf("sg: Failed to attach master async callbac "
163 			"due to status 0x%x!\n", status);
164 	}
165 }
166 
167 static void
168 sgdevgonecb(void *arg)
169 {
170 	struct cam_periph *periph;
171 	struct sg_softc *softc;
172 	struct mtx *mtx;
173 	int i;
174 
175 	periph = (struct cam_periph *)arg;
176 	mtx = cam_periph_mtx(periph);
177 	mtx_lock(mtx);
178 
179 	softc = (struct sg_softc *)periph->softc;
180 	KASSERT(softc->open_count >= 0, ("Negative open count %d",
181 		softc->open_count));
182 
183 	/*
184 	 * When we get this callback, we will get no more close calls from
185 	 * devfs.  So if we have any dangling opens, we need to release the
186 	 * reference held for that particular context.
187 	 */
188 	for (i = 0; i < softc->open_count; i++)
189 		cam_periph_release_locked(periph);
190 
191 	softc->open_count = 0;
192 
193 	/*
194 	 * Release the reference held for the device node, it is gone now.
195 	 */
196 	cam_periph_release_locked(periph);
197 
198 	/*
199 	 * We reference the lock directly here, instead of using
200 	 * cam_periph_unlock().  The reason is that the final call to
201 	 * cam_periph_release_locked() above could result in the periph
202 	 * getting freed.  If that is the case, dereferencing the periph
203 	 * with a cam_periph_unlock() call would cause a page fault.
204 	 */
205 	mtx_unlock(mtx);
206 }
207 
208 static void
209 sgoninvalidate(struct cam_periph *periph)
210 {
211 	struct sg_softc *softc;
212 
213 	softc = (struct sg_softc *)periph->softc;
214 
215 	/*
216 	 * Deregister any async callbacks.
217 	 */
218 	xpt_register_async(0, sgasync, periph, periph->path);
219 
220 	softc->flags |= SG_FLAG_INVALID;
221 
222 	/*
223 	 * Tell devfs this device has gone away, and ask for a callback
224 	 * when it has cleaned up its state.
225 	 */
226 	destroy_dev_sched_cb(softc->dev, sgdevgonecb, periph);
227 
228 	/*
229 	 * XXX Return all queued I/O with ENXIO.
230 	 * XXX Handle any transactions queued to the card
231 	 *     with XPT_ABORT_CCB.
232 	 */
233 
234 }
235 
236 static void
237 sgcleanup(struct cam_periph *periph)
238 {
239 	struct sg_softc *softc;
240 
241 	softc = (struct sg_softc *)periph->softc;
242 
243 	devstat_remove_entry(softc->device_stats);
244 
245 	free(softc, M_DEVBUF);
246 }
247 
248 static void
249 sgasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
250 {
251 	struct cam_periph *periph;
252 
253 	periph = (struct cam_periph *)callback_arg;
254 
255 	switch (code) {
256 	case AC_FOUND_DEVICE:
257 	{
258 		struct ccb_getdev *cgd;
259 		cam_status status;
260 
261 		cgd = (struct ccb_getdev *)arg;
262 		if (cgd == NULL)
263 			break;
264 
265 		if (cgd->protocol != PROTO_SCSI)
266 			break;
267 
268 		/*
269 		 * Allocate a peripheral instance for this device and
270 		 * start the probe process.
271 		 */
272 		status = cam_periph_alloc(sgregister, sgoninvalidate,
273 					  sgcleanup, NULL, "sg",
274 					  CAM_PERIPH_BIO, path,
275 					  sgasync, AC_FOUND_DEVICE, cgd);
276 		if ((status != CAM_REQ_CMP) && (status != CAM_REQ_INPROG)) {
277 			const struct cam_status_entry *entry;
278 
279 			entry = cam_fetch_status_entry(status);
280 			printf("sgasync: Unable to attach new device "
281 				"due to status %#x: %s\n", status, entry ?
282 				entry->status_text : "Unknown");
283 		}
284 		break;
285 	}
286 	default:
287 		cam_periph_async(periph, code, path, arg);
288 		break;
289 	}
290 }
291 
292 static cam_status
293 sgregister(struct cam_periph *periph, void *arg)
294 {
295 	struct sg_softc *softc;
296 	struct ccb_getdev *cgd;
297 	struct ccb_pathinq cpi;
298 	struct make_dev_args args;
299 	int no_tags, error;
300 
301 	cgd = (struct ccb_getdev *)arg;
302 	if (cgd == NULL) {
303 		printf("sgregister: no getdev CCB, can't register device\n");
304 		return (CAM_REQ_CMP_ERR);
305 	}
306 
307 	softc = malloc(sizeof(*softc), M_DEVBUF, M_ZERO | M_NOWAIT);
308 	if (softc == NULL) {
309 		printf("sgregister: Unable to allocate softc\n");
310 		return (CAM_REQ_CMP_ERR);
311 	}
312 
313 	softc->state = SG_STATE_NORMAL;
314 	softc->pd_type = SID_TYPE(&cgd->inq_data);
315 	softc->sg_timeout = SG_DEFAULT_TIMEOUT / SG_DEFAULT_HZ * hz;
316 	softc->sg_user_timeout = SG_DEFAULT_TIMEOUT;
317 	TAILQ_INIT(&softc->rdwr_done);
318 	periph->softc = softc;
319 
320 	xpt_path_inq(&cpi, periph->path);
321 
322 	if (cpi.maxio == 0)
323 		softc->maxio = DFLTPHYS;	/* traditional default */
324 	else if (cpi.maxio > maxphys)
325 		softc->maxio = maxphys;		/* for safety */
326 	else
327 		softc->maxio = cpi.maxio;	/* real value */
328 
329 	/*
330 	 * We pass in 0 for all blocksize, since we don't know what the
331 	 * blocksize of the device is, if it even has a blocksize.
332 	 */
333 	cam_periph_unlock(periph);
334 	no_tags = (cgd->inq_data.flags & SID_CmdQue) == 0;
335 	softc->device_stats = devstat_new_entry("sg",
336 			periph->unit_number, 0,
337 			DEVSTAT_NO_BLOCKSIZE
338 			| (no_tags ? DEVSTAT_NO_ORDERED_TAGS : 0),
339 			softc->pd_type |
340 			XPORT_DEVSTAT_TYPE(cpi.transport) |
341 			DEVSTAT_TYPE_PASS,
342 			DEVSTAT_PRIORITY_PASS);
343 
344 	/*
345 	 * Acquire a reference to the periph before we create the devfs
346 	 * instance for it.  We'll release this reference once the devfs
347 	 * instance has been freed.
348 	 */
349 	if (cam_periph_acquire(periph) != 0) {
350 		xpt_print(periph->path, "%s: lost periph during "
351 			  "registration!\n", __func__);
352 		cam_periph_lock(periph);
353 		return (CAM_REQ_CMP_ERR);
354 	}
355 
356 	/* Register the device */
357 	make_dev_args_init(&args);
358 	args.mda_devsw = &sg_cdevsw;
359 	args.mda_unit = periph->unit_number;
360 	args.mda_uid = UID_ROOT;
361 	args.mda_gid = GID_OPERATOR;
362 	args.mda_mode = 0600;
363 	args.mda_si_drv1 = periph;
364 	error = make_dev_s(&args, &softc->dev, "%s%d",
365 	    periph->periph_name, periph->unit_number);
366 	if (error != 0) {
367 		cam_periph_lock(periph);
368 		cam_periph_release_locked(periph);
369 		return (CAM_REQ_CMP_ERR);
370 	}
371 	if (periph->unit_number < 26) {
372 		(void)make_dev_alias(softc->dev, "sg%c",
373 		    periph->unit_number + 'a');
374 	} else {
375 		(void)make_dev_alias(softc->dev, "sg%c%c",
376 		    ((periph->unit_number / 26) - 1) + 'a',
377 		    (periph->unit_number % 26) + 'a');
378 	}
379 	cam_periph_lock(periph);
380 
381 	/*
382 	 * Add as async callback so that we get
383 	 * notified if this device goes away.
384 	 */
385 	xpt_register_async(AC_LOST_DEVICE, sgasync, periph, periph->path);
386 
387 	if (bootverbose)
388 		xpt_announce_periph(periph, NULL);
389 
390 	return (CAM_REQ_CMP);
391 }
392 
393 static void
394 sgdone(struct cam_periph *periph, union ccb *done_ccb)
395 {
396 	struct sg_softc *softc;
397 	struct ccb_scsiio *csio;
398 
399 	softc = (struct sg_softc *)periph->softc;
400 	csio = &done_ccb->csio;
401 	switch (csio->ccb_h.ccb_type) {
402 	case SG_CCB_RDWR_IO:
403 	{
404 		struct sg_rdwr *rdwr;
405 
406 		devstat_end_transaction(softc->device_stats,
407 					csio->dxfer_len,
408 					csio->tag_action & 0xf,
409 					((csio->ccb_h.flags & CAM_DIR_MASK) ==
410 					CAM_DIR_NONE) ? DEVSTAT_NO_DATA :
411 					(csio->ccb_h.flags & CAM_DIR_OUT) ?
412 					DEVSTAT_WRITE : DEVSTAT_READ,
413 					NULL, NULL);
414 
415 		rdwr = done_ccb->ccb_h.ccb_rdwr;
416 		rdwr->state = SG_RDWR_DONE;
417 		wakeup(rdwr);
418 		break;
419 	}
420 	default:
421 		panic("unknown sg CCB type");
422 	}
423 }
424 
425 static int
426 sgopen(struct cdev *dev, int flags, int fmt, struct thread *td)
427 {
428 	struct cam_periph *periph;
429 	struct sg_softc *softc;
430 	int error = 0;
431 
432 	periph = (struct cam_periph *)dev->si_drv1;
433 	if (cam_periph_acquire(periph) != 0)
434 		return (ENXIO);
435 
436 	/*
437 	 * Don't allow access when we're running at a high securelevel.
438 	 */
439 	error = securelevel_gt(td->td_ucred, 1);
440 	if (error) {
441 		cam_periph_release(periph);
442 		return (error);
443 	}
444 
445 	cam_periph_lock(periph);
446 
447 	softc = (struct sg_softc *)periph->softc;
448 	if (softc->flags & SG_FLAG_INVALID) {
449 		cam_periph_release_locked(periph);
450 		cam_periph_unlock(periph);
451 		return (ENXIO);
452 	}
453 
454 	softc->open_count++;
455 
456 	cam_periph_unlock(periph);
457 
458 	return (error);
459 }
460 
461 static int
462 sgclose(struct cdev *dev, int flag, int fmt, struct thread *td)
463 {
464 	struct cam_periph *periph;
465 	struct sg_softc   *softc;
466 	struct mtx *mtx;
467 
468 	periph = (struct cam_periph *)dev->si_drv1;
469 	mtx = cam_periph_mtx(periph);
470 	mtx_lock(mtx);
471 
472 	softc = periph->softc;
473 	softc->open_count--;
474 
475 	cam_periph_release_locked(periph);
476 
477 	/*
478 	 * We reference the lock directly here, instead of using
479 	 * cam_periph_unlock().  The reason is that the call to
480 	 * cam_periph_release_locked() above could result in the periph
481 	 * getting freed.  If that is the case, dereferencing the periph
482 	 * with a cam_periph_unlock() call would cause a page fault.
483 	 *
484 	 * cam_periph_release() avoids this problem using the same method,
485 	 * but we're manually acquiring and dropping the lock here to
486 	 * protect the open count and avoid another lock acquisition and
487 	 * release.
488 	 */
489 	mtx_unlock(mtx);
490 
491 	return (0);
492 }
493 
494 static int
495 sgioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
496 {
497 	union ccb *ccb;
498 	struct ccb_scsiio *csio;
499 	struct cam_periph *periph;
500 	struct sg_softc *softc;
501 	struct sg_io_hdr *req;
502 	int dir, error;
503 
504 	periph = (struct cam_periph *)dev->si_drv1;
505 	cam_periph_lock(periph);
506 
507 	softc = (struct sg_softc *)periph->softc;
508 	error = 0;
509 
510 	switch (cmd) {
511 	case SG_GET_VERSION_NUM:
512 	{
513 		int *version = (int *)arg;
514 
515 		*version = sg_version;
516 		break;
517 	}
518 	case SG_SET_TIMEOUT:
519 	{
520 		u_int user_timeout = *(u_int *)arg;
521 
522 		softc->sg_user_timeout = user_timeout;
523 		softc->sg_timeout = user_timeout / SG_DEFAULT_HZ * hz;
524 		break;
525 	}
526 	case SG_GET_TIMEOUT:
527 		/*
528 		 * The value is returned directly to the syscall.
529 		 */
530 		td->td_retval[0] = softc->sg_user_timeout;
531 		error = 0;
532 		break;
533 	case SG_IO:
534 		req = (struct sg_io_hdr *)arg;
535 
536 		if (req->cmd_len > IOCDBLEN) {
537 			error = EINVAL;
538 			break;
539 		}
540 
541 		if (req->iovec_count != 0) {
542 			error = EOPNOTSUPP;
543 			break;
544 		}
545 
546 		ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
547 		csio = &ccb->csio;
548 
549 		error = copyin(req->cmdp, &csio->cdb_io.cdb_bytes,
550 		    req->cmd_len);
551 		if (error) {
552 			xpt_release_ccb(ccb);
553 			break;
554 		}
555 
556 		switch(req->dxfer_direction) {
557 		case SG_DXFER_TO_DEV:
558 			dir = CAM_DIR_OUT;
559 			break;
560 		case SG_DXFER_FROM_DEV:
561 			dir = CAM_DIR_IN;
562 			break;
563 		case SG_DXFER_TO_FROM_DEV:
564 			dir = CAM_DIR_BOTH;
565 			break;
566 		case SG_DXFER_NONE:
567 		default:
568 			dir = CAM_DIR_NONE;
569 			break;
570 		}
571 
572 		cam_fill_csio(csio,
573 			      /*retries*/1,
574 			      /*cbfcnp*/NULL,
575 			      dir|CAM_DEV_QFRZDIS,
576 			      MSG_SIMPLE_Q_TAG,
577 			      req->dxferp,
578 			      req->dxfer_len,
579 			      req->mx_sb_len,
580 			      req->cmd_len,
581 			      req->timeout);
582 
583 		error = sgsendccb(periph, ccb);
584 		if (error) {
585 			req->host_status = DID_ERROR;
586 			req->driver_status = DRIVER_INVALID;
587 			xpt_release_ccb(ccb);
588 			break;
589 		}
590 
591 		req->status = csio->scsi_status;
592 		req->masked_status = (csio->scsi_status >> 1) & 0x7f;
593 		sg_scsiio_status(csio, &req->host_status, &req->driver_status);
594 		req->resid = csio->resid;
595 		req->duration = csio->ccb_h.timeout;
596 		req->info = 0;
597 
598 		if ((csio->ccb_h.status & CAM_AUTOSNS_VALID)
599 		    && (req->sbp != NULL)) {
600 			req->sb_len_wr = req->mx_sb_len - csio->sense_resid;
601 			error = copyout(&csio->sense_data, req->sbp,
602 					req->sb_len_wr);
603 		}
604 
605 		xpt_release_ccb(ccb);
606 		break;
607 
608 	case SG_GET_RESERVED_SIZE:
609 	{
610 		int *size = (int *)arg;
611 		*size = DFLTPHYS;
612 		break;
613 	}
614 
615 	case SG_GET_SCSI_ID:
616 	{
617 		struct sg_scsi_id *id = (struct sg_scsi_id *)arg;
618 
619 		id->host_no = cam_sim_path(xpt_path_sim(periph->path));
620 		id->channel = xpt_path_path_id(periph->path);
621 		id->scsi_id = xpt_path_target_id(periph->path);
622 		id->lun = xpt_path_lun_id(periph->path);
623 		id->scsi_type = softc->pd_type;
624 		id->h_cmd_per_lun = 1;
625 		id->d_queue_depth = 1;
626 		id->unused[0] = 0;
627 		id->unused[1] = 0;
628 		break;
629 	}
630 
631 	case SG_GET_SG_TABLESIZE:
632 	{
633 		int *size = (int *)arg;
634 		*size = 0;
635 		break;
636 	}
637 
638 	case SG_EMULATED_HOST:
639 	case SG_SET_TRANSFORM:
640 	case SG_GET_TRANSFORM:
641 	case SG_GET_NUM_WAITING:
642 	case SG_SCSI_RESET:
643 	case SG_GET_REQUEST_TABLE:
644 	case SG_SET_KEEP_ORPHAN:
645 	case SG_GET_KEEP_ORPHAN:
646 	case SG_GET_ACCESS_COUNT:
647 	case SG_SET_FORCE_LOW_DMA:
648 	case SG_GET_LOW_DMA:
649 	case SG_SET_FORCE_PACK_ID:
650 	case SG_GET_PACK_ID:
651 	case SG_SET_RESERVED_SIZE:
652 	case SG_GET_COMMAND_Q:
653 	case SG_SET_COMMAND_Q:
654 	case SG_SET_DEBUG:
655 	case SG_NEXT_CMD_LEN:
656 	default:
657 #ifdef CAMDEBUG
658 		printf("sgioctl: rejecting cmd 0x%lx\n", cmd);
659 #endif
660 		error = ENODEV;
661 		break;
662 	}
663 
664 	cam_periph_unlock(periph);
665 	return (error);
666 }
667 
668 static int
669 sgwrite(struct cdev *dev, struct uio *uio, int ioflag)
670 {
671 	union ccb *ccb;
672 	struct cam_periph *periph;
673 	struct ccb_scsiio *csio;
674 	struct sg_softc *sc;
675 	struct sg_header *hdr;
676 	struct sg_rdwr *rdwr;
677 	u_char cdb_cmd;
678 	char *buf;
679 	int error = 0, cdb_len, buf_len, dir;
680 
681 	periph = dev->si_drv1;
682 	rdwr = malloc(sizeof(*rdwr), M_DEVBUF, M_WAITOK | M_ZERO);
683 	hdr = &rdwr->hdr.hdr;
684 
685 	/* Copy in the header block and sanity check it */
686 	if (uio->uio_resid < sizeof(*hdr)) {
687 		error = EINVAL;
688 		goto out_hdr;
689 	}
690 	error = uiomove(hdr, sizeof(*hdr), uio);
691 	if (error)
692 		goto out_hdr;
693 
694 	/* XXX: We don't support SG 3.x read/write API. */
695 	if (hdr->reply_len < 0) {
696 		error = ENODEV;
697 		goto out_hdr;
698 	}
699 
700 	ccb = xpt_alloc_ccb();
701 	if (ccb == NULL) {
702 		error = ENOMEM;
703 		goto out_hdr;
704 	}
705 	csio = &ccb->csio;
706 
707 	/*
708 	 * Copy in the CDB block.  The designers of the interface didn't
709 	 * bother to provide a size for this in the header, so we have to
710 	 * figure it out ourselves.
711 	 */
712 	if (uio->uio_resid < 1)
713 		goto out_ccb;
714 	error = uiomove(&cdb_cmd, 1, uio);
715 	if (error)
716 		goto out_ccb;
717 	if (hdr->twelve_byte)
718 		cdb_len = 12;
719 	else
720 		cdb_len = scsi_group_len(cdb_cmd);
721 	/*
722 	 * We've already read the first byte of the CDB and advanced the uio
723 	 * pointer.  Just read the rest.
724 	 */
725 	csio->cdb_io.cdb_bytes[0] = cdb_cmd;
726 	error = uiomove(&csio->cdb_io.cdb_bytes[1], cdb_len - 1, uio);
727 	if (error)
728 		goto out_ccb;
729 
730 	/*
731 	 * Now set up the data block.  Again, the designers didn't bother
732 	 * to make this reliable.
733 	 */
734 	buf_len = uio->uio_resid;
735 	if (buf_len != 0) {
736 		buf = malloc(buf_len, M_DEVBUF, M_WAITOK | M_ZERO);
737 		error = uiomove(buf, buf_len, uio);
738 		if (error)
739 			goto out_buf;
740 		dir = CAM_DIR_OUT;
741 	} else if (hdr->reply_len != 0) {
742 		buf = malloc(hdr->reply_len, M_DEVBUF, M_WAITOK | M_ZERO);
743 		buf_len = hdr->reply_len;
744 		dir = CAM_DIR_IN;
745 	} else {
746 		buf = NULL;
747 		buf_len = 0;
748 		dir = CAM_DIR_NONE;
749 	}
750 
751 	cam_periph_lock(periph);
752 	sc = periph->softc;
753 	xpt_setup_ccb(&ccb->ccb_h, periph->path, CAM_PRIORITY_NORMAL);
754 	cam_fill_csio(csio,
755 		      /*retries*/1,
756 		      sgdone,
757 		      dir|CAM_DEV_QFRZDIS,
758 		      MSG_SIMPLE_Q_TAG,
759 		      buf,
760 		      buf_len,
761 		      SG_MAX_SENSE,
762 		      cdb_len,
763 		      sc->sg_timeout);
764 
765 	/*
766 	 * Send off the command and hope that it works. This path does not
767 	 * go through sgstart because the I/O is supposed to be asynchronous.
768 	 */
769 	rdwr->buf = buf;
770 	rdwr->buf_len = buf_len;
771 	rdwr->tag = hdr->pack_id;
772 	rdwr->ccb = ccb;
773 	rdwr->state = SG_RDWR_INPROG;
774 	ccb->ccb_h.ccb_rdwr = rdwr;
775 	ccb->ccb_h.ccb_type = SG_CCB_RDWR_IO;
776 	TAILQ_INSERT_TAIL(&sc->rdwr_done, rdwr, rdwr_link);
777 	error = sgsendrdwr(periph, ccb);
778 	cam_periph_unlock(periph);
779 	return (error);
780 
781 out_buf:
782 	free(buf, M_DEVBUF);
783 out_ccb:
784 	xpt_free_ccb(ccb);
785 out_hdr:
786 	free(rdwr, M_DEVBUF);
787 	return (error);
788 }
789 
790 static int
791 sgread(struct cdev *dev, struct uio *uio, int ioflag)
792 {
793 	struct ccb_scsiio *csio;
794 	struct cam_periph *periph;
795 	struct sg_softc *sc;
796 	struct sg_header *hdr;
797 	struct sg_rdwr *rdwr;
798 	u_short hstat, dstat;
799 	int error, pack_len, reply_len, pack_id;
800 
801 	periph = dev->si_drv1;
802 
803 	/* XXX The pack len field needs to be updated and written out instead
804 	 * of discarded.  Not sure how to do that.
805 	 */
806 	uio->uio_rw = UIO_WRITE;
807 	if ((error = uiomove(&pack_len, 4, uio)) != 0)
808 		return (error);
809 	if ((error = uiomove(&reply_len, 4, uio)) != 0)
810 		return (error);
811 	if ((error = uiomove(&pack_id, 4, uio)) != 0)
812 		return (error);
813 	uio->uio_rw = UIO_READ;
814 
815 	cam_periph_lock(periph);
816 	sc = periph->softc;
817 search:
818 	TAILQ_FOREACH(rdwr, &sc->rdwr_done, rdwr_link) {
819 		if (rdwr->tag == pack_id)
820 			break;
821 	}
822 	if ((rdwr == NULL) || (rdwr->state != SG_RDWR_DONE)) {
823 		if (cam_periph_sleep(periph, rdwr, PCATCH, "sgread", 0) == ERESTART)
824 			return (EAGAIN);
825 		goto search;
826 	}
827 	TAILQ_REMOVE(&sc->rdwr_done, rdwr, rdwr_link);
828 	cam_periph_unlock(periph);
829 
830 	hdr = &rdwr->hdr.hdr;
831 	csio = &rdwr->ccb->csio;
832 	sg_scsiio_status(csio, &hstat, &dstat);
833 	hdr->host_status = hstat;
834 	hdr->driver_status = dstat;
835 	hdr->target_status = csio->scsi_status >> 1;
836 
837 	switch (hstat) {
838 	case DID_OK:
839 	case DID_PASSTHROUGH:
840 	case DID_SOFT_ERROR:
841 		hdr->result = 0;
842 		break;
843 	case DID_NO_CONNECT:
844 	case DID_BUS_BUSY:
845 	case DID_TIME_OUT:
846 		hdr->result = EBUSY;
847 		break;
848 	case DID_BAD_TARGET:
849 	case DID_ABORT:
850 	case DID_PARITY:
851 	case DID_RESET:
852 	case DID_BAD_INTR:
853 	case DID_ERROR:
854 	default:
855 		hdr->result = EIO;
856 		break;
857 	}
858 
859 	if (dstat == DRIVER_SENSE) {
860 		bcopy(&csio->sense_data, hdr->sense_buffer,
861 		      min(csio->sense_len, SG_MAX_SENSE));
862 #ifdef CAMDEBUG
863 		scsi_sense_print(csio);
864 #endif
865 	}
866 
867 	error = uiomove(&hdr->result, sizeof(*hdr) -
868 			offsetof(struct sg_header, result), uio);
869 	if ((error == 0) && (hdr->result == 0))
870 		error = uiomove(rdwr->buf, rdwr->buf_len, uio);
871 
872 	cam_periph_lock(periph);
873 	xpt_free_ccb(rdwr->ccb);
874 	cam_periph_unlock(periph);
875 	free(rdwr->buf, M_DEVBUF);
876 	free(rdwr, M_DEVBUF);
877 	return (error);
878 }
879 
880 static int
881 sgsendccb(struct cam_periph *periph, union ccb *ccb)
882 {
883 	struct sg_softc *softc;
884 	struct cam_periph_map_info mapinfo;
885 	int error, error1;
886 
887 	softc = periph->softc;
888 	bzero(&mapinfo, sizeof(mapinfo));
889 
890 	/*
891 	 * cam_periph_mapmem calls into proc and vm functions that can
892 	 * sleep as well as trigger I/O, so we can't hold the lock.
893 	 * Dropping it here is reasonably safe.
894 	 * The only CCB opcode that is possible here is XPT_SCSI_IO, no
895 	 * need for additional checks.
896 	 */
897 	cam_periph_unlock(periph);
898 	error = cam_periph_mapmem(ccb, &mapinfo, softc->maxio);
899 	cam_periph_lock(periph);
900 	if (error)
901 		return (error);
902 
903 	error = cam_periph_runccb(ccb,
904 				  sgerror,
905 				  CAM_RETRY_SELTO,
906 				  SF_RETRY_UA,
907 				  softc->device_stats);
908 
909 	cam_periph_unlock(periph);
910 	error1 = cam_periph_unmapmem(ccb, &mapinfo);
911 	if (error == 0)
912 		error = error1;
913 	cam_periph_lock(periph);
914 
915 	return (error);
916 }
917 
918 static int
919 sgsendrdwr(struct cam_periph *periph, union ccb *ccb)
920 {
921 	struct sg_softc *softc;
922 
923 	softc = periph->softc;
924 	devstat_start_transaction(softc->device_stats, NULL);
925 	xpt_action(ccb);
926 	return (0);
927 }
928 
929 static int
930 sgerror(union ccb *ccb, uint32_t cam_flags, uint32_t sense_flags)
931 {
932 
933 	return (cam_periph_error(ccb, cam_flags, sense_flags));
934 }
935 
936 static void
937 sg_scsiio_status(struct ccb_scsiio *csio, u_short *hoststat, u_short *drvstat)
938 {
939 	int status;
940 
941 	status = csio->ccb_h.status;
942 
943 	switch (status & CAM_STATUS_MASK) {
944 	case CAM_REQ_CMP:
945 		*hoststat = DID_OK;
946 		*drvstat = 0;
947 		break;
948 	case CAM_REQ_CMP_ERR:
949 		*hoststat = DID_ERROR;
950 		*drvstat = 0;
951 		break;
952 	case CAM_REQ_ABORTED:
953 		*hoststat = DID_ABORT;
954 		*drvstat = 0;
955 		break;
956 	case CAM_REQ_INVALID:
957 		*hoststat = DID_ERROR;
958 		*drvstat = DRIVER_INVALID;
959 		break;
960 	case CAM_DEV_NOT_THERE:
961 		*hoststat = DID_BAD_TARGET;
962 		*drvstat = 0;
963 		break;
964 	case CAM_SEL_TIMEOUT:
965 		*hoststat = DID_NO_CONNECT;
966 		*drvstat = 0;
967 		break;
968 	case CAM_CMD_TIMEOUT:
969 		*hoststat = DID_TIME_OUT;
970 		*drvstat = 0;
971 		break;
972 	case CAM_SCSI_STATUS_ERROR:
973 		*hoststat = DID_ERROR;
974 		*drvstat = 0;
975 		break;
976 	case CAM_SCSI_BUS_RESET:
977 		*hoststat = DID_RESET;
978 		*drvstat = 0;
979 		break;
980 	case CAM_UNCOR_PARITY:
981 		*hoststat = DID_PARITY;
982 		*drvstat = 0;
983 		break;
984 	case CAM_SCSI_BUSY:
985 		*hoststat = DID_BUS_BUSY;
986 		*drvstat = 0;
987 		break;
988 	default:
989 		*hoststat = DID_ERROR;
990 		*drvstat = DRIVER_ERROR;
991 	}
992 
993 	if (status & CAM_AUTOSNS_VALID)
994 		*drvstat = DRIVER_SENSE;
995 }
996 
997 static int
998 scsi_group_len(u_char cmd)
999 {
1000 	int len[] = {6, 10, 10, 12, 12, 12, 10, 10};
1001 	int group;
1002 
1003 	group = (cmd >> 5) & 0x7;
1004 	return (len[group]);
1005 }
1006