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