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