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