1 /* 2 * Implementation of SCSI Processor Target Peripheral driver for CAM. 3 * 4 * Copyright (c) 1998 Justin T. Gibbs. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions, and the following disclaimer, 12 * without modification, immediately at the beginning of the file. 13 * 2. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #include <sys/param.h> 32 #include <sys/queue.h> 33 #include <sys/systm.h> 34 #include <sys/kernel.h> 35 #include <sys/types.h> 36 #include <sys/buf.h> 37 #include <sys/devicestat.h> 38 #include <sys/malloc.h> 39 #include <sys/conf.h> 40 #include <sys/ptio.h> 41 42 #include <cam/cam.h> 43 #include <cam/cam_ccb.h> 44 #include <cam/cam_extend.h> 45 #include <cam/cam_periph.h> 46 #include <cam/cam_xpt_periph.h> 47 #include <cam/cam_debug.h> 48 49 #include <cam/scsi/scsi_all.h> 50 #include <cam/scsi/scsi_message.h> 51 #include <cam/scsi/scsi_pt.h> 52 53 #include "opt_pt.h" 54 55 typedef enum { 56 PT_STATE_PROBE, 57 PT_STATE_NORMAL 58 } pt_state; 59 60 typedef enum { 61 PT_FLAG_NONE = 0x00, 62 PT_FLAG_OPEN = 0x01, 63 PT_FLAG_DEVICE_INVALID = 0x02, 64 PT_FLAG_RETRY_UA = 0x04 65 } pt_flags; 66 67 typedef enum { 68 PT_CCB_BUFFER_IO = 0x01, 69 PT_CCB_WAITING = 0x02, 70 PT_CCB_RETRY_UA = 0x04, 71 PT_CCB_BUFFER_IO_UA = PT_CCB_BUFFER_IO|PT_CCB_RETRY_UA 72 } pt_ccb_state; 73 74 /* Offsets into our private area for storing information */ 75 #define ccb_state ppriv_field0 76 #define ccb_bp ppriv_ptr1 77 78 struct pt_softc { 79 struct buf_queue_head buf_queue; 80 struct devstat device_stats; 81 LIST_HEAD(, ccb_hdr) pending_ccbs; 82 pt_state state; 83 pt_flags flags; 84 union ccb saved_ccb; 85 int io_timeout; 86 }; 87 88 static d_open_t ptopen; 89 static d_close_t ptclose; 90 static d_strategy_t ptstrategy; 91 static periph_init_t ptinit; 92 static void ptasync(void *callback_arg, u_int32_t code, 93 struct cam_path *path, void *arg); 94 static periph_ctor_t ptctor; 95 static periph_oninv_t ptoninvalidate; 96 static periph_dtor_t ptdtor; 97 static periph_start_t ptstart; 98 static void ptdone(struct cam_periph *periph, 99 union ccb *done_ccb); 100 static d_ioctl_t ptioctl; 101 static int pterror(union ccb *ccb, u_int32_t cam_flags, 102 u_int32_t sense_flags); 103 104 void scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries, 105 void (*cbfcnp)(struct cam_periph *, union ccb *), 106 u_int tag_action, int readop, u_int byte2, 107 u_int32_t xfer_len, u_int8_t *data_ptr, 108 u_int8_t sense_len, u_int32_t timeout); 109 110 static struct periph_driver ptdriver = 111 { 112 ptinit, "pt", 113 TAILQ_HEAD_INITIALIZER(ptdriver.units), /* generation */ 0 114 }; 115 116 DATA_SET(periphdriver_set, ptdriver); 117 118 #define PT_CDEV_MAJOR 61 119 120 static struct cdevsw pt_cdevsw = { 121 /* open */ ptopen, 122 /* close */ ptclose, 123 /* read */ physread, 124 /* write */ physwrite, 125 /* ioctl */ ptioctl, 126 /* stop */ nostop, 127 /* reset */ noreset, 128 /* devtotty */ nodevtotty, 129 /* poll */ nopoll, 130 /* mmap */ nommap, 131 /* strategy */ ptstrategy, 132 /* name */ "pt", 133 /* parms */ noparms, 134 /* maj */ PT_CDEV_MAJOR, 135 /* dump */ nodump, 136 /* psize */ nopsize, 137 /* flags */ 0, 138 /* maxio */ 0, 139 /* bmaj */ -1 140 }; 141 142 static struct extend_array *ptperiphs; 143 144 #ifndef SCSI_PT_DEFAULT_TIMEOUT 145 #define SCSI_PT_DEFAULT_TIMEOUT 60 146 #endif 147 148 static int 149 ptopen(dev_t dev, int flags, int fmt, struct proc *p) 150 { 151 struct cam_periph *periph; 152 struct pt_softc *softc; 153 int unit; 154 int error; 155 int s; 156 157 unit = minor(dev); 158 periph = cam_extend_get(ptperiphs, unit); 159 if (periph == NULL) 160 return (ENXIO); 161 162 softc = (struct pt_softc *)periph->softc; 163 164 s = splsoftcam(); 165 if (softc->flags & PT_FLAG_DEVICE_INVALID) { 166 splx(s); 167 return(ENXIO); 168 } 169 170 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 171 ("ptopen: dev=%s (unit %d)\n", devtoname(dev), unit)); 172 173 if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) { 174 splx(s); 175 return (error); /* error code from tsleep */ 176 } 177 178 splx(s); 179 180 if ((softc->flags & PT_FLAG_OPEN) == 0) { 181 if (cam_periph_acquire(periph) != CAM_REQ_CMP) 182 error = ENXIO; 183 else 184 softc->flags |= PT_FLAG_OPEN; 185 } else 186 error = EBUSY; 187 188 cam_periph_unlock(periph); 189 return (error); 190 } 191 192 static int 193 ptclose(dev_t dev, int flag, int fmt, struct proc *p) 194 { 195 struct cam_periph *periph; 196 struct pt_softc *softc; 197 int unit; 198 int error; 199 200 unit = minor(dev); 201 periph = cam_extend_get(ptperiphs, unit); 202 if (periph == NULL) 203 return (ENXIO); 204 205 softc = (struct pt_softc *)periph->softc; 206 207 if ((error = cam_periph_lock(periph, PRIBIO)) != 0) 208 return (error); /* error code from tsleep */ 209 210 softc->flags &= ~PT_FLAG_OPEN; 211 cam_periph_unlock(periph); 212 cam_periph_release(periph); 213 return (0); 214 } 215 216 /* 217 * Actually translate the requested transfer into one the physical driver 218 * can understand. The transfer is described by a buf and will include 219 * only one physical transfer. 220 */ 221 static void 222 ptstrategy(struct buf *bp) 223 { 224 struct cam_periph *periph; 225 struct pt_softc *softc; 226 u_int unit; 227 int s; 228 229 unit = minor(bp->b_dev); 230 periph = cam_extend_get(ptperiphs, unit); 231 if (periph == NULL) { 232 bp->b_error = ENXIO; 233 goto bad; 234 } 235 softc = (struct pt_softc *)periph->softc; 236 237 /* 238 * Mask interrupts so that the pack cannot be invalidated until 239 * after we are in the queue. Otherwise, we might not properly 240 * clean up one of the buffers. 241 */ 242 s = splbio(); 243 244 /* 245 * If the device has been made invalid, error out 246 */ 247 if ((softc->flags & PT_FLAG_DEVICE_INVALID)) { 248 splx(s); 249 bp->b_error = ENXIO; 250 goto bad; 251 } 252 253 /* 254 * Place it in the queue of disk activities for this disk 255 */ 256 bufq_insert_tail(&softc->buf_queue, bp); 257 258 splx(s); 259 260 /* 261 * Schedule ourselves for performing the work. 262 */ 263 xpt_schedule(periph, /* XXX priority */1); 264 265 return; 266 bad: 267 bp->b_flags |= B_ERROR; 268 269 /* 270 * Correctly set the buf to indicate a completed xfer 271 */ 272 bp->b_resid = bp->b_bcount; 273 biodone(bp); 274 } 275 276 static void 277 ptinit(void) 278 { 279 cam_status status; 280 struct cam_path *path; 281 282 /* 283 * Create our extend array for storing the devices we attach to. 284 */ 285 ptperiphs = cam_extend_new(); 286 if (ptperiphs == NULL) { 287 printf("pt: Failed to alloc extend array!\n"); 288 return; 289 } 290 291 /* 292 * Install a global async callback. This callback will 293 * receive async callbacks like "new device found". 294 */ 295 status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, 296 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 297 298 if (status == CAM_REQ_CMP) { 299 struct ccb_setasync csa; 300 301 xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); 302 csa.ccb_h.func_code = XPT_SASYNC_CB; 303 csa.event_enable = AC_FOUND_DEVICE; 304 csa.callback = ptasync; 305 csa.callback_arg = NULL; 306 xpt_action((union ccb *)&csa); 307 status = csa.ccb_h.status; 308 xpt_free_path(path); 309 } 310 311 if (status != CAM_REQ_CMP) { 312 printf("pt: Failed to attach master async callback " 313 "due to status 0x%x!\n", status); 314 } else { 315 /* If we were successfull, register our devsw */ 316 cdevsw_add(&pt_cdevsw); 317 } 318 } 319 320 static cam_status 321 ptctor(struct cam_periph *periph, void *arg) 322 { 323 struct pt_softc *softc; 324 struct ccb_setasync csa; 325 struct ccb_getdev *cgd; 326 327 cgd = (struct ccb_getdev *)arg; 328 if (periph == NULL) { 329 printf("ptregister: periph was NULL!!\n"); 330 return(CAM_REQ_CMP_ERR); 331 } 332 333 if (cgd == NULL) { 334 printf("ptregister: no getdev CCB, can't register device\n"); 335 return(CAM_REQ_CMP_ERR); 336 } 337 338 softc = (struct pt_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT); 339 340 if (softc == NULL) { 341 printf("daregister: Unable to probe new device. " 342 "Unable to allocate softc\n"); 343 return(CAM_REQ_CMP_ERR); 344 } 345 346 bzero(softc, sizeof(*softc)); 347 LIST_INIT(&softc->pending_ccbs); 348 softc->state = PT_STATE_NORMAL; 349 bufq_init(&softc->buf_queue); 350 351 softc->io_timeout = SCSI_PT_DEFAULT_TIMEOUT * 1000; 352 353 periph->softc = softc; 354 355 cam_extend_set(ptperiphs, periph->unit_number, periph); 356 357 /* 358 * The DA driver supports a blocksize, but 359 * we don't know the blocksize until we do 360 * a read capacity. So, set a flag to 361 * indicate that the blocksize is 362 * unavailable right now. We'll clear the 363 * flag as soon as we've done a read capacity. 364 */ 365 devstat_add_entry(&softc->device_stats, "pt", 366 periph->unit_number, 0, 367 DEVSTAT_NO_BLOCKSIZE, 368 cgd->pd_type | DEVSTAT_TYPE_IF_SCSI, 369 DEVSTAT_PRIORITY_OTHER); 370 371 /* 372 * Add async callbacks for bus reset and 373 * bus device reset calls. I don't bother 374 * checking if this fails as, in most cases, 375 * the system will function just fine without 376 * them and the only alternative would be to 377 * not attach the device on failure. 378 */ 379 xpt_setup_ccb(&csa.ccb_h, periph->path, /*priority*/5); 380 csa.ccb_h.func_code = XPT_SASYNC_CB; 381 csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE; 382 csa.callback = ptasync; 383 csa.callback_arg = periph; 384 xpt_action((union ccb *)&csa); 385 386 /* Tell the user we've attached to the device */ 387 xpt_announce_periph(periph, NULL); 388 389 return(CAM_REQ_CMP); 390 } 391 392 static void 393 ptoninvalidate(struct cam_periph *periph) 394 { 395 int s; 396 struct pt_softc *softc; 397 struct buf *q_bp; 398 struct ccb_setasync csa; 399 400 softc = (struct pt_softc *)periph->softc; 401 402 /* 403 * De-register any async callbacks. 404 */ 405 xpt_setup_ccb(&csa.ccb_h, periph->path, 406 /* priority */ 5); 407 csa.ccb_h.func_code = XPT_SASYNC_CB; 408 csa.event_enable = 0; 409 csa.callback = ptasync; 410 csa.callback_arg = periph; 411 xpt_action((union ccb *)&csa); 412 413 softc->flags |= PT_FLAG_DEVICE_INVALID; 414 415 /* 416 * Although the oninvalidate() routines are always called at 417 * splsoftcam, we need to be at splbio() here to keep the buffer 418 * queue from being modified while we traverse it. 419 */ 420 s = splbio(); 421 422 /* 423 * Return all queued I/O with ENXIO. 424 * XXX Handle any transactions queued to the card 425 * with XPT_ABORT_CCB. 426 */ 427 while ((q_bp = bufq_first(&softc->buf_queue)) != NULL){ 428 bufq_remove(&softc->buf_queue, q_bp); 429 q_bp->b_resid = q_bp->b_bcount; 430 q_bp->b_error = ENXIO; 431 q_bp->b_flags |= B_ERROR; 432 biodone(q_bp); 433 } 434 435 splx(s); 436 437 xpt_print_path(periph->path); 438 printf("lost device\n"); 439 } 440 441 static void 442 ptdtor(struct cam_periph *periph) 443 { 444 struct pt_softc *softc; 445 446 softc = (struct pt_softc *)periph->softc; 447 448 devstat_remove_entry(&softc->device_stats); 449 450 cam_extend_release(ptperiphs, periph->unit_number); 451 xpt_print_path(periph->path); 452 printf("removing device entry\n"); 453 free(softc, M_DEVBUF); 454 } 455 456 static void 457 ptasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) 458 { 459 struct cam_periph *periph; 460 461 periph = (struct cam_periph *)callback_arg; 462 switch (code) { 463 case AC_FOUND_DEVICE: 464 { 465 struct ccb_getdev *cgd; 466 cam_status status; 467 468 cgd = (struct ccb_getdev *)arg; 469 470 if (cgd->pd_type != T_PROCESSOR) 471 break; 472 473 /* 474 * Allocate a peripheral instance for 475 * this device and start the probe 476 * process. 477 */ 478 status = cam_periph_alloc(ptctor, ptoninvalidate, ptdtor, 479 ptstart, "pt", CAM_PERIPH_BIO, 480 cgd->ccb_h.path, ptasync, 481 AC_FOUND_DEVICE, cgd); 482 483 if (status != CAM_REQ_CMP 484 && status != CAM_REQ_INPROG) 485 printf("ptasync: Unable to attach to new device " 486 "due to status 0x%x\n", status); 487 break; 488 } 489 case AC_SENT_BDR: 490 case AC_BUS_RESET: 491 { 492 struct pt_softc *softc; 493 struct ccb_hdr *ccbh; 494 int s; 495 496 softc = (struct pt_softc *)periph->softc; 497 s = splsoftcam(); 498 /* 499 * Don't fail on the expected unit attention 500 * that will occur. 501 */ 502 softc->flags |= PT_FLAG_RETRY_UA; 503 for (ccbh = LIST_FIRST(&softc->pending_ccbs); 504 ccbh != NULL; ccbh = LIST_NEXT(ccbh, periph_links.le)) 505 ccbh->ccb_state |= PT_CCB_RETRY_UA; 506 splx(s); 507 /* FALLTHROUGH */ 508 } 509 default: 510 cam_periph_async(periph, code, path, arg); 511 break; 512 } 513 } 514 515 static void 516 ptstart(struct cam_periph *periph, union ccb *start_ccb) 517 { 518 struct pt_softc *softc; 519 struct buf *bp; 520 int s; 521 522 softc = (struct pt_softc *)periph->softc; 523 524 /* 525 * See if there is a buf with work for us to do.. 526 */ 527 s = splbio(); 528 bp = bufq_first(&softc->buf_queue); 529 if (periph->immediate_priority <= periph->pinfo.priority) { 530 CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE, 531 ("queuing for immediate ccb\n")); 532 start_ccb->ccb_h.ccb_state = PT_CCB_WAITING; 533 SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 534 periph_links.sle); 535 periph->immediate_priority = CAM_PRIORITY_NONE; 536 splx(s); 537 wakeup(&periph->ccb_list); 538 } else if (bp == NULL) { 539 splx(s); 540 xpt_release_ccb(start_ccb); 541 } else { 542 int oldspl; 543 544 bufq_remove(&softc->buf_queue, bp); 545 546 devstat_start_transaction(&softc->device_stats); 547 548 scsi_send_receive(&start_ccb->csio, 549 /*retries*/4, 550 ptdone, 551 MSG_SIMPLE_Q_TAG, 552 bp->b_flags & B_READ, 553 /*byte2*/0, 554 bp->b_bcount, 555 bp->b_data, 556 /*sense_len*/SSD_FULL_SIZE, 557 /*timeout*/softc->io_timeout); 558 559 start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO; 560 561 /* 562 * Block out any asyncronous callbacks 563 * while we touch the pending ccb list. 564 */ 565 oldspl = splcam(); 566 LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h, 567 periph_links.le); 568 splx(oldspl); 569 570 start_ccb->ccb_h.ccb_bp = bp; 571 bp = bufq_first(&softc->buf_queue); 572 splx(s); 573 574 xpt_action(start_ccb); 575 576 if (bp != NULL) { 577 /* Have more work to do, so ensure we stay scheduled */ 578 xpt_schedule(periph, /* XXX priority */1); 579 } 580 } 581 } 582 583 static void 584 ptdone(struct cam_periph *periph, union ccb *done_ccb) 585 { 586 struct pt_softc *softc; 587 struct ccb_scsiio *csio; 588 589 softc = (struct pt_softc *)periph->softc; 590 csio = &done_ccb->csio; 591 switch (csio->ccb_h.ccb_state) { 592 case PT_CCB_BUFFER_IO: 593 case PT_CCB_BUFFER_IO_UA: 594 { 595 struct buf *bp; 596 int oldspl; 597 598 bp = (struct buf *)done_ccb->ccb_h.ccb_bp; 599 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 600 int error; 601 int s; 602 int sf; 603 604 if ((csio->ccb_h.ccb_state & PT_CCB_RETRY_UA) != 0) 605 sf = SF_RETRY_UA; 606 else 607 sf = 0; 608 609 sf |= SF_RETRY_SELTO; 610 611 if ((error = pterror(done_ccb, 0, sf)) == ERESTART) { 612 /* 613 * A retry was scheuled, so 614 * just return. 615 */ 616 return; 617 } 618 if (error != 0) { 619 struct buf *q_bp; 620 621 s = splbio(); 622 623 if (error == ENXIO) { 624 /* 625 * Catastrophic error. Mark our device 626 * as invalid. 627 */ 628 xpt_print_path(periph->path); 629 printf("Invalidating device\n"); 630 softc->flags |= PT_FLAG_DEVICE_INVALID; 631 } 632 633 /* 634 * return all queued I/O with EIO, so that 635 * the client can retry these I/Os in the 636 * proper order should it attempt to recover. 637 */ 638 while ((q_bp = bufq_first(&softc->buf_queue)) 639 != NULL) { 640 bufq_remove(&softc->buf_queue, q_bp); 641 q_bp->b_resid = q_bp->b_bcount; 642 q_bp->b_error = EIO; 643 q_bp->b_flags |= B_ERROR; 644 biodone(q_bp); 645 } 646 splx(s); 647 bp->b_error = error; 648 bp->b_resid = bp->b_bcount; 649 bp->b_flags |= B_ERROR; 650 } else { 651 bp->b_resid = csio->resid; 652 bp->b_error = 0; 653 if (bp->b_resid != 0) { 654 /* Short transfer ??? */ 655 bp->b_flags |= B_ERROR; 656 } 657 } 658 if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 659 cam_release_devq(done_ccb->ccb_h.path, 660 /*relsim_flags*/0, 661 /*reduction*/0, 662 /*timeout*/0, 663 /*getcount_only*/0); 664 } else { 665 bp->b_resid = csio->resid; 666 if (bp->b_resid != 0) 667 bp->b_flags |= B_ERROR; 668 } 669 670 /* 671 * Block out any asyncronous callbacks 672 * while we touch the pending ccb list. 673 */ 674 oldspl = splcam(); 675 LIST_REMOVE(&done_ccb->ccb_h, periph_links.le); 676 splx(oldspl); 677 678 devstat_end_transaction(&softc->device_stats, 679 bp->b_bcount - bp->b_resid, 680 done_ccb->csio.tag_action & 0xf, 681 (bp->b_flags & B_READ) ? DEVSTAT_READ 682 : DEVSTAT_WRITE); 683 684 biodone(bp); 685 break; 686 } 687 case PT_CCB_WAITING: 688 /* Caller will release the CCB */ 689 wakeup(&done_ccb->ccb_h.cbfcnp); 690 return; 691 } 692 xpt_release_ccb(done_ccb); 693 } 694 695 static int 696 pterror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 697 { 698 struct pt_softc *softc; 699 struct cam_periph *periph; 700 701 periph = xpt_path_periph(ccb->ccb_h.path); 702 softc = (struct pt_softc *)periph->softc; 703 704 return(cam_periph_error(ccb, cam_flags, sense_flags, 705 &softc->saved_ccb)); 706 } 707 708 static int 709 ptioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 710 { 711 struct cam_periph *periph; 712 struct pt_softc *softc; 713 int unit; 714 int error; 715 716 unit = minor(dev); 717 periph = cam_extend_get(ptperiphs, unit); 718 719 if (periph == NULL) 720 return(ENXIO); 721 722 softc = (struct pt_softc *)periph->softc; 723 724 if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) { 725 return (error); /* error code from tsleep */ 726 } 727 728 switch(cmd) { 729 case PTIOCGETTIMEOUT: 730 if (softc->io_timeout >= 1000) 731 *(int *)addr = softc->io_timeout / 1000; 732 else 733 *(int *)addr = 0; 734 break; 735 case PTIOCSETTIMEOUT: 736 { 737 int s; 738 739 if (*(int *)addr < 1) { 740 error = EINVAL; 741 break; 742 } 743 744 s = splsoftcam(); 745 softc->io_timeout = *(int *)addr * 1000; 746 splx(s); 747 748 break; 749 } 750 default: 751 error = cam_periph_ioctl(periph, cmd, addr, pterror); 752 break; 753 } 754 755 cam_periph_unlock(periph); 756 757 return(error); 758 } 759 760 void 761 scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries, 762 void (*cbfcnp)(struct cam_periph *, union ccb *), 763 u_int tag_action, int readop, u_int byte2, 764 u_int32_t xfer_len, u_int8_t *data_ptr, u_int8_t sense_len, 765 u_int32_t timeout) 766 { 767 struct scsi_send_receive *scsi_cmd; 768 769 scsi_cmd = (struct scsi_send_receive *)&csio->cdb_io.cdb_bytes; 770 scsi_cmd->opcode = readop ? RECEIVE : SEND; 771 scsi_cmd->byte2 = byte2; 772 scsi_ulto3b(xfer_len, scsi_cmd->xfer_len); 773 scsi_cmd->control = 0; 774 775 cam_fill_csio(csio, 776 retries, 777 cbfcnp, 778 /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT, 779 tag_action, 780 data_ptr, 781 xfer_len, 782 sense_len, 783 sizeof(*scsi_cmd), 784 timeout); 785 } 786