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