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/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/kernel.h> 38 #include <sys/types.h> 39 #include <sys/bio.h> 40 #include <sys/malloc.h> 41 #include <sys/fcntl.h> 42 #include <sys/ioccom.h> 43 #include <sys/conf.h> 44 #include <sys/errno.h> 45 #include <sys/devicestat.h> 46 #include <sys/proc.h> 47 #include <sys/uio.h> 48 49 #include <cam/cam.h> 50 #include <cam/cam_ccb.h> 51 #include <cam/cam_periph.h> 52 #include <cam/cam_queue.h> 53 #include <cam/cam_xpt_periph.h> 54 #include <cam/cam_debug.h> 55 #include <cam/cam_sim.h> 56 57 #include <cam/scsi/scsi_all.h> 58 #include <cam/scsi/scsi_message.h> 59 #include <cam/scsi/scsi_sg.h> 60 61 #include <compat/linux/linux_ioctl.h> 62 63 typedef enum { 64 SG_FLAG_OPEN = 0x01, 65 SG_FLAG_LOCKED = 0x02, 66 SG_FLAG_INVALID = 0x04 67 } sg_flags; 68 69 typedef enum { 70 SG_STATE_NORMAL 71 } sg_state; 72 73 typedef enum { 74 SG_RDWR_FREE, 75 SG_RDWR_INPROG, 76 SG_RDWR_DONE 77 } sg_rdwr_state; 78 79 typedef enum { 80 SG_CCB_RDWR_IO, 81 SG_CCB_WAITING 82 } sg_ccb_types; 83 84 #define ccb_type ppriv_field0 85 #define ccb_rdwr ppriv_ptr1 86 87 struct sg_rdwr { 88 TAILQ_ENTRY(sg_rdwr) rdwr_link; 89 int tag; 90 int state; 91 int buf_len; 92 char *buf; 93 union ccb *ccb; 94 union { 95 struct sg_header hdr; 96 struct sg_io_hdr io_hdr; 97 } hdr; 98 }; 99 100 struct sg_softc { 101 sg_state state; 102 sg_flags flags; 103 struct devstat *device_stats; 104 TAILQ_HEAD(, sg_rdwr) rdwr_done; 105 struct cdev *dev; 106 int sg_timeout; 107 int sg_user_timeout; 108 uint8_t pd_type; 109 union ccb saved_ccb; 110 }; 111 112 static d_open_t sgopen; 113 static d_close_t sgclose; 114 static d_ioctl_t sgioctl; 115 static d_write_t sgwrite; 116 static d_read_t sgread; 117 118 static periph_init_t sginit; 119 static periph_ctor_t sgregister; 120 static periph_oninv_t sgoninvalidate; 121 static periph_dtor_t sgcleanup; 122 static periph_start_t sgstart; 123 static void sgasync(void *callback_arg, uint32_t code, 124 struct cam_path *path, void *arg); 125 static void sgdone(struct cam_periph *periph, union ccb *done_ccb); 126 static int sgsendccb(struct cam_periph *periph, union ccb *ccb); 127 static int sgsendrdwr(struct cam_periph *periph, union ccb *ccb); 128 static int sgerror(union ccb *ccb, uint32_t cam_flags, 129 uint32_t sense_flags); 130 static void sg_scsiio_status(struct ccb_scsiio *csio, 131 u_short *hoststat, u_short *drvstat); 132 133 static int scsi_group_len(u_char cmd); 134 135 static struct periph_driver sgdriver = 136 { 137 sginit, "sg", 138 TAILQ_HEAD_INITIALIZER(sgdriver.units), /* gen */ 0 139 }; 140 PERIPHDRIVER_DECLARE(sg, sgdriver); 141 142 static struct cdevsw sg_cdevsw = { 143 .d_version = D_VERSION, 144 .d_flags = D_NEEDGIANT, 145 .d_open = sgopen, 146 .d_close = sgclose, 147 .d_ioctl = sgioctl, 148 .d_write = sgwrite, 149 .d_read = sgread, 150 .d_name = "sg", 151 }; 152 153 static int sg_version = 30125; 154 155 static void 156 sginit(void) 157 { 158 cam_status status; 159 160 /* 161 * Install a global async callback. This callback will receive aync 162 * callbacks like "new device found". 163 */ 164 status = xpt_register_async(AC_FOUND_DEVICE, sgasync, NULL, NULL); 165 166 if (status != CAM_REQ_CMP) { 167 printf("sg: Failed to attach master async callbac " 168 "due to status 0x%x!\n", status); 169 } 170 } 171 172 static void 173 sgoninvalidate(struct cam_periph *periph) 174 { 175 struct sg_softc *softc; 176 177 softc = (struct sg_softc *)periph->softc; 178 179 /* 180 * Deregister any async callbacks. 181 */ 182 xpt_register_async(0, sgasync, periph, periph->path); 183 184 softc->flags |= SG_FLAG_INVALID; 185 186 /* 187 * XXX Return all queued I/O with ENXIO. 188 * XXX Handle any transactions queued to the card 189 * with XPT_ABORT_CCB. 190 */ 191 192 if (bootverbose) { 193 xpt_print(periph->path, "lost device\n"); 194 } 195 } 196 197 static void 198 sgcleanup(struct cam_periph *periph) 199 { 200 struct sg_softc *softc; 201 202 softc = (struct sg_softc *)periph->softc; 203 devstat_remove_entry(softc->device_stats); 204 destroy_dev(softc->dev); 205 if (bootverbose) { 206 xpt_print(periph->path, "removing device entry\n"); 207 } 208 free(softc, M_DEVBUF); 209 } 210 211 static void 212 sgasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg) 213 { 214 struct cam_periph *periph; 215 216 periph = (struct cam_periph *)callback_arg; 217 218 switch (code) { 219 case AC_FOUND_DEVICE: 220 { 221 struct ccb_getdev *cgd; 222 cam_status status; 223 224 cgd = (struct ccb_getdev *)arg; 225 if (cgd == NULL) 226 break; 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, "sg", 234 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 printf("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 printf("sgregister: periph was NULL!!\n"); 262 return (CAM_REQ_CMP_ERR); 263 } 264 265 if (cgd == NULL) { 266 printf("sgregister: no getdev CCB, can't register device\n"); 267 return (CAM_REQ_CMP_ERR); 268 } 269 270 softc = malloc(sizeof(*softc), M_DEVBUF, M_ZERO | M_NOWAIT); 271 if (softc == NULL) { 272 printf("sgregister: Unable to allocate softc\n"); 273 return (CAM_REQ_CMP_ERR); 274 } 275 276 softc->state = SG_STATE_NORMAL; 277 softc->pd_type = SID_TYPE(&cgd->inq_data); 278 softc->sg_timeout = SG_DEFAULT_TIMEOUT / SG_DEFAULT_HZ * hz; 279 softc->sg_user_timeout = SG_DEFAULT_TIMEOUT; 280 TAILQ_INIT(&softc->rdwr_done); 281 periph->softc = softc; 282 283 /* 284 * We pass in 0 for all blocksize, since we don't know what the 285 * blocksize of the device is, if it even has a blocksize. 286 */ 287 cam_periph_unlock(periph); 288 no_tags = (cgd->inq_data.flags & SID_CmdQue) == 0; 289 softc->device_stats = devstat_new_entry("sg", 290 periph->unit_number, 0, 291 DEVSTAT_NO_BLOCKSIZE 292 | (no_tags ? DEVSTAT_NO_ORDERED_TAGS : 0), 293 softc->pd_type | 294 DEVSTAT_TYPE_IF_SCSI | 295 DEVSTAT_TYPE_PASS, 296 DEVSTAT_PRIORITY_PASS); 297 298 /* Register the device */ 299 softc->dev = make_dev(&sg_cdevsw, periph->unit_number, 300 UID_ROOT, GID_OPERATOR, 0600, "%s%d", 301 periph->periph_name, periph->unit_number); 302 (void)make_dev_alias(softc->dev, "sg%c", 'a' + periph->unit_number); 303 cam_periph_lock(periph); 304 softc->dev->si_drv1 = periph; 305 306 /* 307 * Add as async callback so that we get 308 * notified if this device goes away. 309 */ 310 xpt_register_async(AC_LOST_DEVICE, sgasync, periph, periph->path); 311 312 if (bootverbose) 313 xpt_announce_periph(periph, NULL); 314 315 return (CAM_REQ_CMP); 316 } 317 318 static void 319 sgstart(struct cam_periph *periph, union ccb *start_ccb) 320 { 321 struct sg_softc *softc; 322 323 softc = (struct sg_softc *)periph->softc; 324 325 switch (softc->state) { 326 case SG_STATE_NORMAL: 327 start_ccb->ccb_h.ccb_type = SG_CCB_WAITING; 328 SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 329 periph_links.sle); 330 periph->immediate_priority = CAM_PRIORITY_NONE; 331 wakeup(&periph->ccb_list); 332 break; 333 } 334 } 335 336 static void 337 sgdone(struct cam_periph *periph, union ccb *done_ccb) 338 { 339 struct sg_softc *softc; 340 struct ccb_scsiio *csio; 341 342 softc = (struct sg_softc *)periph->softc; 343 csio = &done_ccb->csio; 344 switch (csio->ccb_h.ccb_type) { 345 case SG_CCB_WAITING: 346 /* Caller will release the CCB */ 347 wakeup(&done_ccb->ccb_h.cbfcnp); 348 return; 349 case SG_CCB_RDWR_IO: 350 { 351 struct sg_rdwr *rdwr; 352 int state; 353 354 devstat_end_transaction(softc->device_stats, 355 csio->dxfer_len, 356 csio->tag_action & 0xf, 357 ((csio->ccb_h.flags & CAM_DIR_MASK) == 358 CAM_DIR_NONE) ? DEVSTAT_NO_DATA : 359 (csio->ccb_h.flags & CAM_DIR_OUT) ? 360 DEVSTAT_WRITE : DEVSTAT_READ, 361 NULL, NULL); 362 363 rdwr = done_ccb->ccb_h.ccb_rdwr; 364 state = rdwr->state; 365 rdwr->state = SG_RDWR_DONE; 366 wakeup(rdwr); 367 break; 368 } 369 default: 370 panic("unknown sg CCB type"); 371 } 372 } 373 374 static int 375 sgopen(struct cdev *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 *)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 error = securelevel_gt(td->td_ucred, 1); 389 if (error) 390 return (error); 391 392 cam_periph_lock(periph); 393 394 softc = (struct sg_softc *)periph->softc; 395 if (softc->flags & SG_FLAG_INVALID) { 396 cam_periph_unlock(periph); 397 return (ENXIO); 398 } 399 400 if ((softc->flags & SG_FLAG_OPEN) == 0) { 401 softc->flags |= SG_FLAG_OPEN; 402 cam_periph_unlock(periph); 403 } else { 404 /* Device closes aren't symmetrical, fix up the refcount. */ 405 cam_periph_unlock(periph); 406 cam_periph_release(periph); 407 } 408 409 return (error); 410 } 411 412 static int 413 sgclose(struct cdev *dev, int flag, int fmt, struct thread *td) 414 { 415 struct cam_periph *periph; 416 struct sg_softc *softc; 417 418 periph = (struct cam_periph *)dev->si_drv1; 419 if (periph == NULL) 420 return (ENXIO); 421 422 cam_periph_lock(periph); 423 424 softc = (struct sg_softc *)periph->softc; 425 softc->flags &= ~SG_FLAG_OPEN; 426 427 cam_periph_unlock(periph); 428 cam_periph_release(periph); 429 430 return (0); 431 } 432 433 static int 434 sgioctl(struct cdev *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 *)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 (cmd) { 453 case LINUX_SCSI_GET_BUS_NUMBER: { 454 int busno; 455 456 busno = xpt_path_path_id(periph->path); 457 error = copyout(&busno, arg, 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, arg, sizeof(idlun)); 468 break; 469 } 470 case SG_GET_VERSION_NUM: 471 case LINUX_SG_GET_VERSION_NUM: 472 error = copyout(&sg_version, arg, 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(arg, &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 td->td_retval[0] = softc->sg_user_timeout; 491 error = 0; 492 break; 493 case SG_IO: 494 case LINUX_SG_IO: 495 error = copyin(arg, &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, arg, 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, arg, 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, arg, 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 printf("sgioctl: rejecting cmd 0x%lx\n", 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 cdev *dev, struct uio *uio, int ioflag) 651 { 652 union ccb *ccb; 653 struct cam_periph *periph; 654 struct ccb_scsiio *csio; 655 struct sg_softc *sc; 656 struct sg_header *hdr; 657 struct sg_rdwr *rdwr; 658 u_char cdb_cmd; 659 char *buf; 660 int error = 0, cdb_len, buf_len, dir; 661 662 periph = dev->si_drv1; 663 rdwr = malloc(sizeof(*rdwr), M_DEVBUF, M_WAITOK | M_ZERO); 664 hdr = &rdwr->hdr.hdr; 665 666 /* Copy in the header block and sanity check it */ 667 if (uio->uio_resid < sizeof(*hdr)) { 668 error = EINVAL; 669 goto out_hdr; 670 } 671 error = uiomove(hdr, sizeof(*hdr), uio); 672 if (error) 673 goto out_hdr; 674 675 ccb = xpt_alloc_ccb(); 676 if (ccb == NULL) { 677 error = ENOMEM; 678 goto out_hdr; 679 } 680 csio = &ccb->csio; 681 682 /* 683 * Copy in the CDB block. The designers of the interface didn't 684 * bother to provide a size for this in the header, so we have to 685 * figure it out ourselves. 686 */ 687 if (uio->uio_resid < 1) 688 goto out_ccb; 689 error = uiomove(&cdb_cmd, 1, uio); 690 if (error) 691 goto out_ccb; 692 if (hdr->twelve_byte) 693 cdb_len = 12; 694 else 695 cdb_len = scsi_group_len(cdb_cmd); 696 /* 697 * We've already read the first byte of the CDB and advanced the uio 698 * pointer. Just read the rest. 699 */ 700 csio->cdb_io.cdb_bytes[0] = cdb_cmd; 701 error = uiomove(&csio->cdb_io.cdb_bytes[1], cdb_len - 1, uio); 702 if (error) 703 goto out_ccb; 704 705 /* 706 * Now set up the data block. Again, the designers didn't bother 707 * to make this reliable. 708 */ 709 buf_len = uio->uio_resid; 710 if (buf_len != 0) { 711 buf = malloc(buf_len, M_DEVBUF, M_WAITOK | M_ZERO); 712 error = uiomove(buf, buf_len, uio); 713 if (error) 714 goto out_buf; 715 dir = CAM_DIR_OUT; 716 } else if (hdr->reply_len != 0) { 717 buf = malloc(hdr->reply_len, M_DEVBUF, M_WAITOK | M_ZERO); 718 buf_len = hdr->reply_len; 719 dir = CAM_DIR_IN; 720 } else { 721 buf = NULL; 722 buf_len = 0; 723 dir = CAM_DIR_NONE; 724 } 725 726 cam_periph_lock(periph); 727 sc = periph->softc; 728 xpt_setup_ccb(&ccb->ccb_h, periph->path, /*priority*/5); 729 cam_fill_csio(csio, 730 /*retries*/1, 731 sgdone, 732 dir|CAM_DEV_QFRZDIS, 733 MSG_SIMPLE_Q_TAG, 734 buf, 735 buf_len, 736 SG_MAX_SENSE, 737 cdb_len, 738 sc->sg_timeout); 739 740 /* 741 * Send off the command and hope that it works. This path does not 742 * go through sgstart because the I/O is supposed to be asynchronous. 743 */ 744 rdwr->buf = buf; 745 rdwr->buf_len = buf_len; 746 rdwr->tag = hdr->pack_id; 747 rdwr->ccb = ccb; 748 rdwr->state = SG_RDWR_INPROG; 749 ccb->ccb_h.ccb_rdwr = rdwr; 750 ccb->ccb_h.ccb_type = SG_CCB_RDWR_IO; 751 TAILQ_INSERT_TAIL(&sc->rdwr_done, rdwr, rdwr_link); 752 error = sgsendrdwr(periph, ccb); 753 cam_periph_unlock(periph); 754 return (error); 755 756 out_buf: 757 free(buf, M_DEVBUF); 758 out_ccb: 759 xpt_free_ccb(ccb); 760 out_hdr: 761 free(rdwr, M_DEVBUF); 762 return (error); 763 } 764 765 static int 766 sgread(struct cdev *dev, struct uio *uio, int ioflag) 767 { 768 struct ccb_scsiio *csio; 769 struct cam_periph *periph; 770 struct sg_softc *sc; 771 struct sg_header *hdr; 772 struct sg_rdwr *rdwr; 773 u_short hstat, dstat; 774 int error, pack_len, reply_len, pack_id; 775 776 periph = dev->si_drv1; 777 778 /* XXX The pack len field needs to be updated and written out instead 779 * of discarded. Not sure how to do that. 780 */ 781 uio->uio_rw = UIO_WRITE; 782 if ((error = uiomove(&pack_len, 4, uio)) != 0) 783 return (error); 784 if ((error = uiomove(&reply_len, 4, uio)) != 0) 785 return (error); 786 if ((error = uiomove(&pack_id, 4, uio)) != 0) 787 return (error); 788 uio->uio_rw = UIO_READ; 789 790 cam_periph_lock(periph); 791 sc = periph->softc; 792 search: 793 TAILQ_FOREACH(rdwr, &sc->rdwr_done, rdwr_link) { 794 if (rdwr->tag == pack_id) 795 break; 796 } 797 if ((rdwr == NULL) || (rdwr->state != SG_RDWR_DONE)) { 798 if (msleep(rdwr, periph->sim->mtx, PCATCH, "sgread", 0) == ERESTART) 799 return (EAGAIN); 800 goto search; 801 } 802 TAILQ_REMOVE(&sc->rdwr_done, rdwr, rdwr_link); 803 cam_periph_unlock(periph); 804 805 hdr = &rdwr->hdr.hdr; 806 csio = &rdwr->ccb->csio; 807 sg_scsiio_status(csio, &hstat, &dstat); 808 hdr->host_status = hstat; 809 hdr->driver_status = dstat; 810 hdr->target_status = csio->scsi_status >> 1; 811 812 switch (hstat) { 813 case DID_OK: 814 case DID_PASSTHROUGH: 815 case DID_SOFT_ERROR: 816 hdr->result = 0; 817 break; 818 case DID_NO_CONNECT: 819 case DID_BUS_BUSY: 820 case DID_TIME_OUT: 821 hdr->result = EBUSY; 822 break; 823 case DID_BAD_TARGET: 824 case DID_ABORT: 825 case DID_PARITY: 826 case DID_RESET: 827 case DID_BAD_INTR: 828 case DID_ERROR: 829 default: 830 hdr->result = EIO; 831 break; 832 } 833 834 if (dstat == DRIVER_SENSE) { 835 bcopy(&csio->sense_data, hdr->sense_buffer, 836 min(csio->sense_len, SG_MAX_SENSE)); 837 #ifdef CAMDEBUG 838 scsi_sense_print(csio); 839 #endif 840 } 841 842 error = uiomove(&hdr->result, sizeof(*hdr) - 843 offsetof(struct sg_header, result), uio); 844 if ((error == 0) && (hdr->result == 0)) 845 error = uiomove(rdwr->buf, rdwr->buf_len, uio); 846 847 cam_periph_lock(periph); 848 xpt_free_ccb(rdwr->ccb); 849 cam_periph_unlock(periph); 850 free(rdwr->buf, M_DEVBUF); 851 free(rdwr, M_DEVBUF); 852 return (error); 853 } 854 855 static int 856 sgsendccb(struct cam_periph *periph, union ccb *ccb) 857 { 858 struct sg_softc *softc; 859 struct cam_periph_map_info mapinfo; 860 int error, need_unmap = 0; 861 862 softc = periph->softc; 863 if (((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) 864 && (ccb->csio.data_ptr != NULL)) { 865 bzero(&mapinfo, sizeof(mapinfo)); 866 867 /* 868 * cam_periph_mapmem calls into proc and vm functions that can 869 * sleep as well as trigger I/O, so we can't hold the lock. 870 * Dropping it here is reasonably safe. 871 */ 872 cam_periph_unlock(periph); 873 error = cam_periph_mapmem(ccb, &mapinfo); 874 cam_periph_lock(periph); 875 if (error) 876 return (error); 877 need_unmap = 1; 878 } 879 880 error = cam_periph_runccb(ccb, 881 sgerror, 882 CAM_RETRY_SELTO, 883 SF_RETRY_UA, 884 softc->device_stats); 885 886 if (need_unmap) 887 cam_periph_unmapmem(ccb, &mapinfo); 888 889 return (error); 890 } 891 892 static int 893 sgsendrdwr(struct cam_periph *periph, union ccb *ccb) 894 { 895 struct sg_softc *softc; 896 897 softc = periph->softc; 898 devstat_start_transaction(softc->device_stats, NULL); 899 xpt_action(ccb); 900 return (0); 901 } 902 903 static int 904 sgerror(union ccb *ccb, uint32_t cam_flags, uint32_t sense_flags) 905 { 906 struct cam_periph *periph; 907 struct sg_softc *softc; 908 909 periph = xpt_path_periph(ccb->ccb_h.path); 910 softc = (struct sg_softc *)periph->softc; 911 912 return (cam_periph_error(ccb, cam_flags, sense_flags, 913 &softc->saved_ccb)); 914 } 915 916 static void 917 sg_scsiio_status(struct ccb_scsiio *csio, u_short *hoststat, u_short *drvstat) 918 { 919 int status; 920 921 status = csio->ccb_h.status; 922 923 switch (status & CAM_STATUS_MASK) { 924 case CAM_REQ_CMP: 925 *hoststat = DID_OK; 926 *drvstat = 0; 927 break; 928 case CAM_REQ_CMP_ERR: 929 *hoststat = DID_ERROR; 930 *drvstat = 0; 931 break; 932 case CAM_REQ_ABORTED: 933 *hoststat = DID_ABORT; 934 *drvstat = 0; 935 break; 936 case CAM_REQ_INVALID: 937 *hoststat = DID_ERROR; 938 *drvstat = DRIVER_INVALID; 939 break; 940 case CAM_DEV_NOT_THERE: 941 *hoststat = DID_BAD_TARGET; 942 *drvstat = 0; 943 case CAM_SEL_TIMEOUT: 944 *hoststat = DID_NO_CONNECT; 945 *drvstat = 0; 946 break; 947 case CAM_CMD_TIMEOUT: 948 *hoststat = DID_TIME_OUT; 949 *drvstat = 0; 950 break; 951 case CAM_SCSI_STATUS_ERROR: 952 *hoststat = DID_ERROR; 953 *drvstat = 0; 954 case CAM_SCSI_BUS_RESET: 955 *hoststat = DID_RESET; 956 *drvstat = 0; 957 break; 958 case CAM_UNCOR_PARITY: 959 *hoststat = DID_PARITY; 960 *drvstat = 0; 961 break; 962 case CAM_SCSI_BUSY: 963 *hoststat = DID_BUS_BUSY; 964 *drvstat = 0; 965 default: 966 *hoststat = DID_ERROR; 967 *drvstat = DRIVER_ERROR; 968 } 969 970 if (status & CAM_AUTOSNS_VALID) 971 *drvstat = DRIVER_SENSE; 972 } 973 974 static int 975 scsi_group_len(u_char cmd) 976 { 977 int len[] = {6, 10, 10, 12, 12, 12, 10, 10}; 978 int group; 979 980 group = (cmd >> 5) & 0x7; 981 return (len[group]); 982 } 983 984