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