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