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