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