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