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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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