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