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