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