kernel/bus: Remove some unused variables and put others in #ifdef...
[dragonfly.git] / sys / bus / cam / scsi / scsi_sg.c
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/conf.h>
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/types.h>
37 #include <sys/bio.h>
38 #include <sys/malloc.h>
39 #include <sys/fcntl.h>
40 #include <sys/errno.h>
41 #include <sys/devicestat.h>
42 #include <sys/proc.h>
43 #include <sys/uio.h>
44 #include <sys/device.h>
45 #include <sys/sysmsg.h>
46
47 #include "../cam.h"
48 #include "../cam_ccb.h"
49 #include "../cam_periph.h"
50 #include "../cam_queue.h"
51 #include "../cam_xpt_periph.h"
52 #include "../cam_debug.h"
53 #include "../cam_sim.h"
54
55 #include <emulation/linux/linux_ioctl.h>
56
57 #include "scsi_all.h"
58 #include "scsi_message.h"
59 #include "scsi_sg.h"
60
61 typedef enum {
62         SG_FLAG_OPEN            = 0x01,
63         SG_FLAG_LOCKED          = 0x02,
64         SG_FLAG_INVALID         = 0x04
65 } sg_flags;
66
67 typedef enum {
68         SG_STATE_NORMAL
69 } sg_state;
70
71 typedef enum {
72         SG_RDWR_FREE,
73         SG_RDWR_INPROG,
74         SG_RDWR_DONE
75 } sg_rdwr_state;
76
77 typedef enum {
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 },
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
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
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
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
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
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 (bootverbose)
309                 xpt_announce_periph(periph, NULL);
310
311         return (CAM_REQ_CMP);
312 }
313
314 static void
315 sgstart(struct cam_periph *periph, union ccb *start_ccb)
316 {
317         struct sg_softc *softc;
318
319         softc = (struct sg_softc *)periph->softc;
320
321         switch (softc->state) {
322         case SG_STATE_NORMAL:
323                 start_ccb->ccb_h.ccb_type = SG_CCB_WAITING;
324                 SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
325                                   periph_links.sle);
326                 periph->immediate_priority = CAM_PRIORITY_NONE;
327                 wakeup(&periph->ccb_list);
328                 break;
329         }
330 }
331
332 static void
333 sgdone(struct cam_periph *periph, union ccb *done_ccb)
334 {
335         struct sg_softc *softc;
336         struct ccb_scsiio *csio;
337
338         softc = (struct sg_softc *)periph->softc;
339         csio = &done_ccb->csio;
340         switch (csio->ccb_h.ccb_type) {
341         case SG_CCB_WAITING:
342                 /* Caller will release the CCB */
343                 wakeup(&done_ccb->ccb_h.cbfcnp);
344                 return;
345         case SG_CCB_RDWR_IO:
346         {
347                 struct sg_rdwr *rdwr;
348
349                 devstat_end_transaction(
350                         &softc->device_stats,
351                         csio->dxfer_len,
352                         csio->tag_action & 0xf,
353                         ((csio->ccb_h.flags & CAM_DIR_MASK) ==
354                           CAM_DIR_NONE) ? DEVSTAT_NO_DATA :
355                             ((csio->ccb_h.flags & CAM_DIR_OUT) ?
356                              DEVSTAT_WRITE : DEVSTAT_READ));
357
358                 rdwr = done_ccb->ccb_h.ccb_rdwr;
359                 rdwr->state = SG_RDWR_DONE;
360                 wakeup(rdwr);
361                 break;
362         }
363         default:
364                 panic("unknown sg CCB type");
365         }
366 }
367
368 static int
369 sgopen(struct dev_open_args *ap)
370 /*cdev_t dev, int flags, int fmt, struct thread *td)*/
371 {
372         struct cam_periph *periph;
373         struct sg_softc *softc;
374         int error = 0;
375
376         periph = (struct cam_periph *)ap->a_head.a_dev->si_drv1;
377         if (periph == NULL)
378                 return (ENXIO);
379
380         /*
381          * Don't allow access when we're running at a high securelevel.
382          */
383         if (securelevel > 1) {
384                 cam_periph_unlock(periph);
385                 cam_periph_release(periph);
386                 return(EPERM);
387         }
388         cam_periph_lock(periph);
389
390         softc = (struct sg_softc *)periph->softc;
391         if (softc->flags & SG_FLAG_INVALID) {
392                 cam_periph_unlock(periph);
393                 return (ENXIO);
394         }
395
396         if ((softc->flags & SG_FLAG_OPEN) == 0) {
397                 softc->flags |= SG_FLAG_OPEN;
398                 cam_periph_unlock(periph);
399         } else {
400                 /* Device closes aren't symmetrical, fix up the refcount. */
401                 cam_periph_unlock(periph);
402                 cam_periph_release(periph);
403         }
404
405         return (error);
406 }
407
408 static int
409 sgclose(struct dev_close_args *ap)
410 /* cdev_t dev, int flag, int fmt, struct thread *td) */
411 {
412         struct cam_periph *periph;
413         struct sg_softc *softc;
414
415         periph = (struct cam_periph *)ap->a_head.a_dev->si_drv1;
416         if (periph == NULL)
417                 return (ENXIO);
418
419         cam_periph_lock(periph);
420
421         softc = (struct sg_softc *)periph->softc;
422         softc->flags &= ~SG_FLAG_OPEN;
423
424         cam_periph_unlock(periph);
425         cam_periph_release(periph);
426
427         return (0);
428 }
429
430 static int
431 sgioctl(struct dev_ioctl_args *ap)
432 /* cdev_t dev, u_long cmd, caddr_t arg, int flag, struct thread *td) */
433 {
434         union ccb *ccb;
435         struct ccb_scsiio *csio;
436         struct cam_periph *periph;
437         struct sg_softc *softc;
438         struct sg_io_hdr req;
439         int dir, error;
440
441         periph = (struct cam_periph *)ap->a_head.a_dev->si_drv1;
442         if (periph == NULL)
443                 return (ENXIO);
444
445         cam_periph_lock(periph);
446
447         softc = (struct sg_softc *)periph->softc;
448         error = 0;
449
450         switch (ap->a_cmd) {
451         case LINUX_SCSI_GET_BUS_NUMBER: {
452                 int busno;
453
454                 busno = xpt_path_path_id(periph->path);
455                 error = copyout(&busno, ap->a_data, sizeof(busno));
456                 break;
457         }
458         case LINUX_SCSI_GET_IDLUN: {
459                 struct scsi_idlun idlun;
460                 struct cam_sim *sim;
461
462                 idlun.dev_id = xpt_path_target_id(periph->path);
463                 sim = xpt_path_sim(periph->path);
464                 idlun.host_unique_id = sim->unit_number;
465                 error = copyout(&idlun, ap->a_data, sizeof(idlun));
466                 break;
467         }
468         case SG_GET_VERSION_NUM:
469         case LINUX_SG_GET_VERSION_NUM:
470                 error = copyout(&sg_version, ap->a_data, sizeof(sg_version));
471                 break;
472         case SG_SET_TIMEOUT:
473         case LINUX_SG_SET_TIMEOUT: {
474                 u_int user_timeout;
475
476                 error = copyin(ap->a_data, &user_timeout, sizeof(u_int));
477                 if (error == 0) {
478                         softc->sg_user_timeout = user_timeout;
479                         softc->sg_timeout = user_timeout / SG_DEFAULT_HZ * hz;
480                 }
481                 break;
482         }
483         case SG_GET_TIMEOUT:
484         case LINUX_SG_GET_TIMEOUT:
485                 /*
486                  * The value is returned directly to the syscall.
487                  */
488                 ap->a_sysmsg->sm_result.iresult = softc->sg_user_timeout;
489                 error = 0;
490                 break;
491         case SG_IO:
492         case LINUX_SG_IO:
493                 error = copyin(ap->a_data, &req, sizeof(req));
494                 if (error)
495                         break;
496
497                 if (req.cmd_len > IOCDBLEN) {
498                         error = EINVAL;
499                         break;
500                 }
501
502                 if (req.iovec_count != 0) {
503                         error = EOPNOTSUPP;
504                         break;
505                 }
506
507                 ccb = cam_periph_getccb(periph, /*priority*/5);
508                 csio = &ccb->csio;
509
510                 error = copyin(req.cmdp, &csio->cdb_io.cdb_bytes,
511                     req.cmd_len);
512                 if (error) {
513                         xpt_release_ccb(ccb);
514                         break;
515                 }
516
517                 switch(req.dxfer_direction) {
518                 case SG_DXFER_TO_DEV:
519                         dir = CAM_DIR_OUT;
520                         break;
521                 case SG_DXFER_FROM_DEV:
522                         dir = CAM_DIR_IN;
523                         break;
524                 case SG_DXFER_TO_FROM_DEV:
525                         dir = CAM_DIR_IN | CAM_DIR_OUT;
526                         break;
527                 case SG_DXFER_NONE:
528                 default:
529                         dir = CAM_DIR_NONE;
530                         break;
531                 }
532
533                 cam_fill_csio(csio,
534                               /*retries*/1,
535                               sgdone,
536                               dir|CAM_DEV_QFRZDIS,
537                               MSG_SIMPLE_Q_TAG,
538                               req.dxferp,
539                               req.dxfer_len,
540                               req.mx_sb_len,
541                               req.cmd_len,
542                               req.timeout);
543
544                 error = sgsendccb(periph, ccb);
545                 if (error) {
546                         req.host_status = DID_ERROR;
547                         req.driver_status = DRIVER_INVALID;
548                         xpt_release_ccb(ccb);
549                         break;
550                 }
551
552                 req.status = csio->scsi_status;
553                 req.masked_status = (csio->scsi_status >> 1) & 0x7f;
554                 sg_scsiio_status(csio, &req.host_status, &req.driver_status);
555                 req.resid = csio->resid;
556                 req.duration = csio->ccb_h.timeout;
557                 req.info = 0;
558
559                 error = copyout(&req, ap->a_data, sizeof(req));
560                 if ((error == 0) && (csio->ccb_h.status & CAM_AUTOSNS_VALID)
561                     && (req.sbp != NULL)) {
562                         req.sb_len_wr = req.mx_sb_len - csio->sense_resid;
563                         error = copyout(&csio->sense_data, req.sbp,
564                                         req.sb_len_wr);
565                 }
566
567                 xpt_release_ccb(ccb);
568                 break;
569
570         case SG_GET_RESERVED_SIZE:
571         case LINUX_SG_GET_RESERVED_SIZE: {
572                 int size = 32768;
573
574                 error = copyout(&size, ap->a_data, sizeof(size));
575                 break;
576         }
577
578         case SG_GET_SCSI_ID:
579         case LINUX_SG_GET_SCSI_ID:
580         {
581                 struct sg_scsi_id id;
582
583                 id.host_no = 0; /* XXX */
584                 id.channel = xpt_path_path_id(periph->path);
585                 id.scsi_id = xpt_path_target_id(periph->path);
586                 id.lun = xpt_path_lun_id(periph->path);
587                 id.scsi_type = softc->pd_type;
588                 id.h_cmd_per_lun = 1;
589                 id.d_queue_depth = 1;
590                 id.unused[0] = 0;
591                 id.unused[1] = 0;
592
593                 error = copyout(&id, ap->a_data, sizeof(id));
594                 break;
595         }
596
597         case SG_EMULATED_HOST:
598         case SG_SET_TRANSFORM:
599         case SG_GET_TRANSFORM:
600         case SG_GET_NUM_WAITING:
601         case SG_SCSI_RESET:
602         case SG_GET_REQUEST_TABLE:
603         case SG_SET_KEEP_ORPHAN:
604         case SG_GET_KEEP_ORPHAN:
605         case SG_GET_ACCESS_COUNT:
606         case SG_SET_FORCE_LOW_DMA:
607         case SG_GET_LOW_DMA:
608         case SG_GET_SG_TABLESIZE:
609         case SG_SET_FORCE_PACK_ID:
610         case SG_GET_PACK_ID:
611         case SG_SET_RESERVED_SIZE:
612         case SG_GET_COMMAND_Q:
613         case SG_SET_COMMAND_Q:
614         case SG_SET_DEBUG:
615         case SG_NEXT_CMD_LEN:
616         case LINUX_SG_EMULATED_HOST:
617         case LINUX_SG_SET_TRANSFORM:
618         case LINUX_SG_GET_TRANSFORM:
619         case LINUX_SG_GET_NUM_WAITING:
620         case LINUX_SG_SCSI_RESET:
621         case LINUX_SG_GET_REQUEST_TABLE:
622         case LINUX_SG_SET_KEEP_ORPHAN:
623         case LINUX_SG_GET_KEEP_ORPHAN:
624         case LINUX_SG_GET_ACCESS_COUNT:
625         case LINUX_SG_SET_FORCE_LOW_DMA:
626         case LINUX_SG_GET_LOW_DMA:
627         case LINUX_SG_GET_SG_TABLESIZE:
628         case LINUX_SG_SET_FORCE_PACK_ID:
629         case LINUX_SG_GET_PACK_ID:
630         case LINUX_SG_SET_RESERVED_SIZE:
631         case LINUX_SG_GET_COMMAND_Q:
632         case LINUX_SG_SET_COMMAND_Q:
633         case LINUX_SG_SET_DEBUG:
634         case LINUX_SG_NEXT_CMD_LEN:
635         default:
636 #ifdef CAMDEBUG
637                 kprintf("sgioctl: rejecting cmd 0x%lx\n", ap->a_cmd);
638 #endif
639                 error = ENODEV;
640                 break;
641         }
642
643         cam_periph_unlock(periph);
644         return (error);
645 }
646
647 static int
648 sgwrite(struct dev_write_args *ap)
649 /*cdev_t dev, struct uio *uio, int ioflag)*/
650 {
651         union ccb *ccb;
652         struct cam_periph *periph;
653         struct ccb_scsiio *csio;
654         struct sg_softc *sc;
655         struct sg_header *hdr;
656         struct sg_rdwr *rdwr;
657         u_char cdb_cmd;
658         char *buf;
659         int error = 0, cdb_len, buf_len, dir;
660         struct uio *uio = ap->a_uio;
661
662         periph = ap->a_head.a_dev->si_drv1;
663         rdwr = kmalloc(sizeof(*rdwr), M_DEVBUF, M_WAITOK | M_ZERO);
664         hdr = &rdwr->hdr.hdr;
665
666         /* Copy in the header block and sanity check it */
667         if (uio->uio_resid < sizeof(*hdr)) {
668                 error = EINVAL;
669                 goto out_hdr;
670         }
671         error = uiomove((char *)hdr, sizeof(*hdr), uio);
672         if (error)
673                 goto out_hdr;
674
675         ccb = xpt_alloc_ccb();
676         if (ccb == NULL) {
677                 error = ENOMEM;
678                 goto out_hdr;
679         }
680         csio = &ccb->csio;
681
682         /*
683          * Copy in the CDB block.  The designers of the interface didn't
684          * bother to provide a size for this in the header, so we have to
685          * figure it out ourselves.
686          */
687         if (uio->uio_resid < 1)
688                 goto out_ccb;
689         error = uiomove(&cdb_cmd, 1, uio);
690         if (error)
691                 goto out_ccb;
692         if (hdr->twelve_byte)
693                 cdb_len = 12;
694         else
695                 cdb_len = scsi_group_len(cdb_cmd);
696         /*
697          * We've already read the first byte of the CDB and advanced the uio
698          * pointer.  Just read the rest.
699          */
700         csio->cdb_io.cdb_bytes[0] = cdb_cmd;
701         error = uiomove(&csio->cdb_io.cdb_bytes[1], cdb_len - 1, uio);
702         if (error)
703                 goto out_ccb;
704
705         /*
706          * Now set up the data block.  Again, the designers didn't bother
707          * to make this reliable.
708          */
709         buf_len = uio->uio_resid;
710         if (buf_len != 0) {
711                 buf = kmalloc(buf_len, M_DEVBUF, M_WAITOK | M_ZERO);
712                 error = uiomove(buf, buf_len, uio);
713                 if (error)
714                         goto out_buf;
715                 dir = CAM_DIR_OUT;
716         } else if (hdr->reply_len != 0) {
717                 buf = kmalloc(hdr->reply_len, M_DEVBUF, M_WAITOK | M_ZERO);
718                 buf_len = hdr->reply_len;
719                 dir = CAM_DIR_IN;
720         } else {
721                 buf = NULL;
722                 buf_len = 0;
723                 dir = CAM_DIR_NONE;
724         }
725
726         cam_periph_lock(periph);
727         sc = periph->softc;
728         xpt_setup_ccb(&ccb->ccb_h, periph->path, /*priority*/5);
729         cam_fill_csio(csio,
730                       /*retries*/1,
731                       sgdone,
732                       dir|CAM_DEV_QFRZDIS,
733                       MSG_SIMPLE_Q_TAG,
734                       buf,
735                       buf_len,
736                       SG_MAX_SENSE,
737                       cdb_len,
738                       sc->sg_timeout);
739
740         /*
741          * Send off the command and hope that it works. This path does not
742          * go through sgstart because the I/O is supposed to be asynchronous.
743          */
744         rdwr->buf = buf;
745         rdwr->buf_len = buf_len;
746         rdwr->tag = hdr->pack_id;
747         rdwr->ccb = ccb;
748         rdwr->state = SG_RDWR_INPROG;
749         ccb->ccb_h.ccb_rdwr = rdwr;
750         ccb->ccb_h.ccb_type = SG_CCB_RDWR_IO;
751         TAILQ_INSERT_TAIL(&sc->rdwr_done, rdwr, rdwr_link);
752         error = sgsendrdwr(periph, ccb);
753         cam_periph_unlock(periph);
754         return (error);
755
756 out_buf:
757         kfree(buf, M_DEVBUF);
758 out_ccb:
759         xpt_free_ccb(ccb);
760 out_hdr:
761         kfree(rdwr, M_DEVBUF);
762         return (error);
763 }
764
765 static int
766 sgread(struct dev_read_args *ap)
767 /*cdev_t dev, struct uio *uio, int ioflag)*/
768 {
769         struct ccb_scsiio *csio;
770         struct cam_periph *periph;
771         struct sg_softc *sc;
772         struct sg_header *hdr;
773         struct sg_rdwr *rdwr;
774         u_short hstat, dstat;
775         int error, pack_len, reply_len, pack_id;
776         struct uio *uio = ap->a_uio;
777
778         periph = ap->a_head.a_dev->si_drv1;
779
780         /* XXX The pack len field needs to be updated and written out instead
781          * of discarded.  Not sure how to do that.
782          */
783         uio->uio_rw = UIO_WRITE;
784         if ((error = uiomove((char *)&pack_len, 4, uio)) != 0)
785                 return (error);
786         if ((error = uiomove((char *)&reply_len, 4, uio)) != 0)
787                 return (error);
788         if ((error = uiomove((char *)&pack_id, 4, uio)) != 0)
789                 return (error);
790         uio->uio_rw = UIO_READ;
791
792         cam_periph_lock(periph);
793         sc = periph->softc;
794 search:
795         TAILQ_FOREACH(rdwr, &sc->rdwr_done, rdwr_link) {
796                 if (rdwr->tag == pack_id)
797                         break;
798         }
799         if (rdwr == NULL) {
800                 cam_periph_unlock(periph);
801                 if (tsleep(&hstat, PCATCH, "sgnull", 0) == ERESTART)
802                         return(EAGAIN);
803                 cam_periph_lock(periph);
804                 goto search;
805         }
806         if (rdwr->state != SG_RDWR_DONE) {
807                 tsleep_interlock(rdwr, PCATCH);
808                 cam_periph_unlock(periph);
809                 if (rdwr->state != SG_RDWR_DONE) {
810                     if (tsleep(rdwr, PCATCH | PINTERLOCKED, "sgread", 0) ==
811                         ERESTART) {
812                                 return (EAGAIN);
813                     }
814                 }
815                 cam_periph_lock(periph);
816                 goto search;
817         }
818         TAILQ_REMOVE(&sc->rdwr_done, rdwr, rdwr_link);
819         cam_periph_unlock(periph);
820
821         hdr = &rdwr->hdr.hdr;
822         csio = &rdwr->ccb->csio;
823         sg_scsiio_status(csio, &hstat, &dstat);
824         hdr->host_status = hstat;
825         hdr->driver_status = dstat;
826         hdr->target_status = csio->scsi_status >> 1;
827
828         switch (hstat) {
829         case DID_OK:
830         case DID_PASSTHROUGH:
831         case DID_SOFT_ERROR:
832                 hdr->result = 0;
833                 break;
834         case DID_NO_CONNECT:
835         case DID_BUS_BUSY:
836         case DID_TIME_OUT:
837                 hdr->result = EBUSY;
838                 break;
839         case DID_BAD_TARGET:
840         case DID_ABORT:
841         case DID_PARITY:
842         case DID_RESET:
843         case DID_BAD_INTR:
844         case DID_ERROR:
845         default:
846                 hdr->result = EIO;
847                 break;
848         }
849
850         if (dstat == DRIVER_SENSE) {
851                 bcopy(&csio->sense_data, hdr->sense_buffer,
852                       min(csio->sense_len, SG_MAX_SENSE));
853 #ifdef CAMDEBUG
854                 scsi_sense_print(csio);
855 #endif
856         }
857
858         error = uiomove((char *)&hdr->result, sizeof(*hdr) -
859                         offsetof(struct sg_header, result), uio);
860         if ((error == 0) && (hdr->result == 0))
861                 error = uiomove(rdwr->buf, rdwr->buf_len, uio);
862
863         cam_periph_lock(periph);
864         xpt_free_ccb(rdwr->ccb);
865         cam_periph_unlock(periph);
866         kfree(rdwr->buf, M_DEVBUF);
867         kfree(rdwr, M_DEVBUF);
868         return (error);
869 }
870
871 static int
872 sgsendccb(struct cam_periph *periph, union ccb *ccb)
873 {
874         struct sg_softc *softc;
875         struct cam_periph_map_info mapinfo;
876         int error, need_unmap = 0;
877
878         softc = periph->softc;
879         if (((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)
880             && (ccb->csio.data_ptr != NULL)) {
881                 bzero(&mapinfo, sizeof(mapinfo));
882
883                 /*
884                  * cam_periph_mapmem calls into proc and vm functions that can
885                  * sleep as well as trigger I/O, so we can't hold the lock.
886                  * Dropping it here is reasonably safe.
887                  */
888                 cam_periph_unlock(periph);
889                 error = cam_periph_mapmem(ccb, &mapinfo);
890                 cam_periph_lock(periph);
891                 if (error)
892                         return (error);
893                 need_unmap = 1;
894         }
895
896         error = cam_periph_runccb(ccb, sgerror, CAM_RETRY_SELTO,
897                                   SF_RETRY_UA, &softc->device_stats);
898
899         if (need_unmap)
900                 cam_periph_unmapmem(ccb, &mapinfo);
901
902         return (error);
903 }
904
905 static int
906 sgsendrdwr(struct cam_periph *periph, union ccb *ccb)
907 {
908         struct sg_softc *softc;
909
910         softc = periph->softc;
911         devstat_start_transaction(&softc->device_stats);
912         xpt_action(ccb);
913         return (0);
914 }
915
916 static int
917 sgerror(union ccb *ccb, uint32_t cam_flags, uint32_t sense_flags)
918 {
919         struct cam_periph *periph;
920         struct sg_softc *softc;
921
922         periph = xpt_path_periph(ccb->ccb_h.path);
923         softc = (struct sg_softc *)periph->softc;
924
925         return (cam_periph_error(ccb, cam_flags, sense_flags,
926                                  &softc->saved_ccb));
927 }
928
929 static void
930 sg_scsiio_status(struct ccb_scsiio *csio, u_short *hoststat, u_short *drvstat)
931 {
932         int status;
933
934         status = csio->ccb_h.status;
935
936         switch (status & CAM_STATUS_MASK) {
937         case CAM_REQ_CMP:
938                 *hoststat = DID_OK;
939                 *drvstat = 0;
940                 break;
941         case CAM_REQ_CMP_ERR:
942                 *hoststat = DID_ERROR;
943                 *drvstat = 0;
944                 break;
945         case CAM_REQ_ABORTED:
946                 *hoststat = DID_ABORT;
947                 *drvstat = 0;
948                 break;
949         case CAM_REQ_INVALID:
950                 *hoststat = DID_ERROR;
951                 *drvstat = DRIVER_INVALID;
952                 break;
953         case CAM_DEV_NOT_THERE:
954                 *hoststat = DID_BAD_TARGET;
955                 *drvstat = 0;
956                 break;
957         case CAM_SEL_TIMEOUT:
958                 *hoststat = DID_NO_CONNECT;
959                 *drvstat = 0;
960                 break;
961         case CAM_CMD_TIMEOUT:
962                 *hoststat = DID_TIME_OUT;
963                 *drvstat = 0;
964                 break;
965         case CAM_SCSI_STATUS_ERROR:
966                 *hoststat = DID_ERROR;
967                 *drvstat = 0;
968                 break;
969         case CAM_SCSI_BUS_RESET:
970                 *hoststat = DID_RESET;
971                 *drvstat = 0;
972                 break;
973         case CAM_UNCOR_PARITY:
974                 *hoststat = DID_PARITY;
975                 *drvstat = 0;
976                 break;
977         case CAM_SCSI_BUSY:
978                 *hoststat = DID_BUS_BUSY;
979                 *drvstat = 0;
980                 break;
981         default:
982                 *hoststat = DID_ERROR;
983                 *drvstat = DRIVER_ERROR;
984         }
985
986         if (status & CAM_AUTOSNS_VALID)
987                 *drvstat = DRIVER_SENSE;
988 }
989
990 static int
991 scsi_group_len(u_char cmd)
992 {
993         int len[] = {6, 10, 10, 12, 12, 12, 10, 10};
994         int group;
995
996         group = (cmd >> 5) & 0x7;
997         return (len[group]);
998 }