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