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