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