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: src/sys/cam/scsi/scsi_pt.c,v 1.17 2000/01/17 06:27:37 mjacob Exp $ 29 * $DragonFly: src/sys/bus/cam/scsi/scsi_pt.c,v 1.11 2004/05/19 22:52:38 dillon Exp $ 30 */ 31 32 #include <sys/param.h> 33 #include <sys/queue.h> 34 #include <sys/systm.h> 35 #include <sys/kernel.h> 36 #include <sys/types.h> 37 #include <sys/buf.h> 38 #include <sys/devicestat.h> 39 #include <sys/malloc.h> 40 #include <sys/conf.h> 41 #include <sys/ptio.h> 42 #include <sys/buf2.h> 43 44 #include "../cam.h" 45 #include "../cam_ccb.h" 46 #include "../cam_extend.h" 47 #include "../cam_periph.h" 48 #include "../cam_xpt_periph.h" 49 #include "../cam_debug.h" 50 51 #include "scsi_all.h" 52 #include "scsi_message.h" 53 #include "scsi_pt.h" 54 55 #include "opt_pt.h" 56 57 typedef enum { 58 PT_STATE_PROBE, 59 PT_STATE_NORMAL 60 } pt_state; 61 62 typedef enum { 63 PT_FLAG_NONE = 0x00, 64 PT_FLAG_OPEN = 0x01, 65 PT_FLAG_DEVICE_INVALID = 0x02, 66 PT_FLAG_RETRY_UA = 0x04 67 } pt_flags; 68 69 typedef enum { 70 PT_CCB_BUFFER_IO = 0x01, 71 PT_CCB_WAITING = 0x02, 72 PT_CCB_RETRY_UA = 0x04, 73 PT_CCB_BUFFER_IO_UA = PT_CCB_BUFFER_IO|PT_CCB_RETRY_UA 74 } pt_ccb_state; 75 76 /* Offsets into our private area for storing information */ 77 #define ccb_state ppriv_field0 78 #define ccb_bp ppriv_ptr1 79 80 struct pt_softc { 81 struct buf_queue_head buf_queue; 82 struct devstat device_stats; 83 LIST_HEAD(, ccb_hdr) pending_ccbs; 84 pt_state state; 85 pt_flags flags; 86 union ccb saved_ccb; 87 int io_timeout; 88 dev_t dev; 89 }; 90 91 static d_open_t ptopen; 92 static d_close_t ptclose; 93 static d_strategy_t ptstrategy; 94 static periph_init_t ptinit; 95 static void ptasync(void *callback_arg, u_int32_t code, 96 struct cam_path *path, void *arg); 97 static periph_ctor_t ptctor; 98 static periph_oninv_t ptoninvalidate; 99 static periph_dtor_t ptdtor; 100 static periph_start_t ptstart; 101 static void ptdone(struct cam_periph *periph, 102 union ccb *done_ccb); 103 static d_ioctl_t ptioctl; 104 static int pterror(union ccb *ccb, u_int32_t cam_flags, 105 u_int32_t sense_flags); 106 107 void scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries, 108 void (*cbfcnp)(struct cam_periph *, union ccb *), 109 u_int tag_action, int readop, u_int byte2, 110 u_int32_t xfer_len, u_int8_t *data_ptr, 111 u_int8_t sense_len, u_int32_t timeout); 112 113 static struct periph_driver ptdriver = 114 { 115 ptinit, "pt", 116 TAILQ_HEAD_INITIALIZER(ptdriver.units), /* generation */ 0 117 }; 118 119 DATA_SET(periphdriver_set, ptdriver); 120 121 #define PT_CDEV_MAJOR 61 122 123 static struct cdevsw pt_cdevsw = { 124 /* name */ "pt", 125 /* maj */ PT_CDEV_MAJOR, 126 /* flags */ 0, 127 /* port */ NULL, 128 /* clone */ NULL, 129 130 /* open */ ptopen, 131 /* close */ ptclose, 132 /* read */ physread, 133 /* write */ physwrite, 134 /* ioctl */ ptioctl, 135 /* poll */ nopoll, 136 /* mmap */ nommap, 137 /* strategy */ ptstrategy, 138 /* dump */ nodump, 139 /* psize */ nopsize 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 thread *td) 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, 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 thread *td) 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, 0)) != 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 } 315 } 316 317 static cam_status 318 ptctor(struct cam_periph *periph, void *arg) 319 { 320 struct pt_softc *softc; 321 struct ccb_setasync csa; 322 struct ccb_getdev *cgd; 323 324 cgd = (struct ccb_getdev *)arg; 325 if (periph == NULL) { 326 printf("ptregister: periph was NULL!!\n"); 327 return(CAM_REQ_CMP_ERR); 328 } 329 330 if (cgd == NULL) { 331 printf("ptregister: no getdev CCB, can't register device\n"); 332 return(CAM_REQ_CMP_ERR); 333 } 334 335 softc = malloc(sizeof(*softc), M_DEVBUF, M_INTWAIT | M_ZERO); 336 LIST_INIT(&softc->pending_ccbs); 337 softc->state = PT_STATE_NORMAL; 338 bufq_init(&softc->buf_queue); 339 340 softc->io_timeout = SCSI_PT_DEFAULT_TIMEOUT * 1000; 341 342 periph->softc = softc; 343 344 cam_extend_set(ptperiphs, periph->unit_number, periph); 345 346 devstat_add_entry(&softc->device_stats, "pt", 347 periph->unit_number, 0, 348 DEVSTAT_NO_BLOCKSIZE, 349 SID_TYPE(&cgd->inq_data) | DEVSTAT_TYPE_IF_SCSI, 350 DEVSTAT_PRIORITY_OTHER); 351 352 cdevsw_add(&pt_cdevsw, -1, periph->unit_number); 353 make_dev(&pt_cdevsw, periph->unit_number, UID_ROOT, 354 GID_OPERATOR, 0600, "%s%d", periph->periph_name, 355 periph->unit_number); 356 /* 357 * Add async callbacks for bus reset and 358 * bus device reset calls. I don't bother 359 * checking if this fails as, in most cases, 360 * the system will function just fine without 361 * them and the only alternative would be to 362 * not attach the device on failure. 363 */ 364 xpt_setup_ccb(&csa.ccb_h, periph->path, /*priority*/5); 365 csa.ccb_h.func_code = XPT_SASYNC_CB; 366 csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE; 367 csa.callback = ptasync; 368 csa.callback_arg = periph; 369 xpt_action((union ccb *)&csa); 370 371 /* Tell the user we've attached to the device */ 372 xpt_announce_periph(periph, NULL); 373 374 return(CAM_REQ_CMP); 375 } 376 377 static void 378 ptoninvalidate(struct cam_periph *periph) 379 { 380 int s; 381 struct pt_softc *softc; 382 struct buf *q_bp; 383 struct ccb_setasync csa; 384 385 softc = (struct pt_softc *)periph->softc; 386 387 /* 388 * De-register any async callbacks. 389 */ 390 xpt_setup_ccb(&csa.ccb_h, periph->path, 391 /* priority */ 5); 392 csa.ccb_h.func_code = XPT_SASYNC_CB; 393 csa.event_enable = 0; 394 csa.callback = ptasync; 395 csa.callback_arg = periph; 396 xpt_action((union ccb *)&csa); 397 398 softc->flags |= PT_FLAG_DEVICE_INVALID; 399 400 /* 401 * Although the oninvalidate() routines are always called at 402 * splsoftcam, we need to be at splbio() here to keep the buffer 403 * queue from being modified while we traverse it. 404 */ 405 s = splbio(); 406 407 /* 408 * Return all queued I/O with ENXIO. 409 * XXX Handle any transactions queued to the card 410 * with XPT_ABORT_CCB. 411 */ 412 while ((q_bp = bufq_first(&softc->buf_queue)) != NULL){ 413 bufq_remove(&softc->buf_queue, q_bp); 414 q_bp->b_resid = q_bp->b_bcount; 415 q_bp->b_error = ENXIO; 416 q_bp->b_flags |= B_ERROR; 417 biodone(q_bp); 418 } 419 420 splx(s); 421 422 xpt_print_path(periph->path); 423 printf("lost device\n"); 424 } 425 426 static void 427 ptdtor(struct cam_periph *periph) 428 { 429 struct pt_softc *softc; 430 431 softc = (struct pt_softc *)periph->softc; 432 433 devstat_remove_entry(&softc->device_stats); 434 435 cam_extend_release(ptperiphs, periph->unit_number); 436 xpt_print_path(periph->path); 437 printf("removing device entry\n"); 438 cdevsw_remove(&pt_cdevsw, -1, periph->unit_number); 439 free(softc, M_DEVBUF); 440 } 441 442 static void 443 ptasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) 444 { 445 struct cam_periph *periph; 446 447 periph = (struct cam_periph *)callback_arg; 448 switch (code) { 449 case AC_FOUND_DEVICE: 450 { 451 struct ccb_getdev *cgd; 452 cam_status status; 453 454 cgd = (struct ccb_getdev *)arg; 455 456 if (SID_TYPE(&cgd->inq_data) != T_PROCESSOR) 457 break; 458 459 /* 460 * Allocate a peripheral instance for 461 * this device and start the probe 462 * process. 463 */ 464 status = cam_periph_alloc(ptctor, ptoninvalidate, ptdtor, 465 ptstart, "pt", CAM_PERIPH_BIO, 466 cgd->ccb_h.path, ptasync, 467 AC_FOUND_DEVICE, cgd); 468 469 if (status != CAM_REQ_CMP 470 && status != CAM_REQ_INPROG) 471 printf("ptasync: Unable to attach to new device " 472 "due to status 0x%x\n", status); 473 break; 474 } 475 case AC_SENT_BDR: 476 case AC_BUS_RESET: 477 { 478 struct pt_softc *softc; 479 struct ccb_hdr *ccbh; 480 int s; 481 482 softc = (struct pt_softc *)periph->softc; 483 s = splsoftcam(); 484 /* 485 * Don't fail on the expected unit attention 486 * that will occur. 487 */ 488 softc->flags |= PT_FLAG_RETRY_UA; 489 for (ccbh = LIST_FIRST(&softc->pending_ccbs); 490 ccbh != NULL; ccbh = LIST_NEXT(ccbh, periph_links.le)) 491 ccbh->ccb_state |= PT_CCB_RETRY_UA; 492 splx(s); 493 /* FALLTHROUGH */ 494 } 495 default: 496 cam_periph_async(periph, code, path, arg); 497 break; 498 } 499 } 500 501 static void 502 ptstart(struct cam_periph *periph, union ccb *start_ccb) 503 { 504 struct pt_softc *softc; 505 struct buf *bp; 506 int s; 507 508 softc = (struct pt_softc *)periph->softc; 509 510 /* 511 * See if there is a buf with work for us to do.. 512 */ 513 s = splbio(); 514 bp = bufq_first(&softc->buf_queue); 515 if (periph->immediate_priority <= periph->pinfo.priority) { 516 CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE, 517 ("queuing for immediate ccb\n")); 518 start_ccb->ccb_h.ccb_state = PT_CCB_WAITING; 519 SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 520 periph_links.sle); 521 periph->immediate_priority = CAM_PRIORITY_NONE; 522 splx(s); 523 wakeup(&periph->ccb_list); 524 } else if (bp == NULL) { 525 splx(s); 526 xpt_release_ccb(start_ccb); 527 } else { 528 int oldspl; 529 530 bufq_remove(&softc->buf_queue, bp); 531 532 devstat_start_transaction(&softc->device_stats); 533 534 scsi_send_receive(&start_ccb->csio, 535 /*retries*/4, 536 ptdone, 537 MSG_SIMPLE_Q_TAG, 538 bp->b_flags & B_READ, 539 /*byte2*/0, 540 bp->b_bcount, 541 bp->b_data, 542 /*sense_len*/SSD_FULL_SIZE, 543 /*timeout*/softc->io_timeout); 544 545 start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO; 546 547 /* 548 * Block out any asyncronous callbacks 549 * while we touch the pending ccb list. 550 */ 551 oldspl = splcam(); 552 LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h, 553 periph_links.le); 554 splx(oldspl); 555 556 start_ccb->ccb_h.ccb_bp = bp; 557 bp = bufq_first(&softc->buf_queue); 558 splx(s); 559 560 xpt_action(start_ccb); 561 562 if (bp != NULL) { 563 /* Have more work to do, so ensure we stay scheduled */ 564 xpt_schedule(periph, /* XXX priority */1); 565 } 566 } 567 } 568 569 static void 570 ptdone(struct cam_periph *periph, union ccb *done_ccb) 571 { 572 struct pt_softc *softc; 573 struct ccb_scsiio *csio; 574 575 softc = (struct pt_softc *)periph->softc; 576 csio = &done_ccb->csio; 577 switch (csio->ccb_h.ccb_state) { 578 case PT_CCB_BUFFER_IO: 579 case PT_CCB_BUFFER_IO_UA: 580 { 581 struct buf *bp; 582 int oldspl; 583 584 bp = (struct buf *)done_ccb->ccb_h.ccb_bp; 585 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 586 int error; 587 int s; 588 int sf; 589 590 if ((csio->ccb_h.ccb_state & PT_CCB_RETRY_UA) != 0) 591 sf = SF_RETRY_UA; 592 else 593 sf = 0; 594 595 sf |= SF_RETRY_SELTO; 596 597 if ((error = pterror(done_ccb, 0, sf)) == ERESTART) { 598 /* 599 * A retry was scheuled, so 600 * just return. 601 */ 602 return; 603 } 604 if (error != 0) { 605 struct buf *q_bp; 606 607 s = splbio(); 608 609 if (error == ENXIO) { 610 /* 611 * Catastrophic error. Mark our device 612 * as invalid. 613 */ 614 xpt_print_path(periph->path); 615 printf("Invalidating device\n"); 616 softc->flags |= PT_FLAG_DEVICE_INVALID; 617 } 618 619 /* 620 * return all queued I/O with EIO, so that 621 * the client can retry these I/Os in the 622 * proper order should it attempt to recover. 623 */ 624 while ((q_bp = bufq_first(&softc->buf_queue)) 625 != NULL) { 626 bufq_remove(&softc->buf_queue, q_bp); 627 q_bp->b_resid = q_bp->b_bcount; 628 q_bp->b_error = EIO; 629 q_bp->b_flags |= B_ERROR; 630 biodone(q_bp); 631 } 632 splx(s); 633 bp->b_error = error; 634 bp->b_resid = bp->b_bcount; 635 bp->b_flags |= B_ERROR; 636 } else { 637 bp->b_resid = csio->resid; 638 bp->b_error = 0; 639 if (bp->b_resid != 0) { 640 /* Short transfer ??? */ 641 bp->b_flags |= B_ERROR; 642 } 643 } 644 if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 645 cam_release_devq(done_ccb->ccb_h.path, 646 /*relsim_flags*/0, 647 /*reduction*/0, 648 /*timeout*/0, 649 /*getcount_only*/0); 650 } else { 651 bp->b_resid = csio->resid; 652 if (bp->b_resid != 0) 653 bp->b_flags |= B_ERROR; 654 } 655 656 /* 657 * Block out any asyncronous callbacks 658 * while we touch the pending ccb list. 659 */ 660 oldspl = splcam(); 661 LIST_REMOVE(&done_ccb->ccb_h, periph_links.le); 662 splx(oldspl); 663 664 devstat_end_transaction_buf(&softc->device_stats, bp); 665 biodone(bp); 666 break; 667 } 668 case PT_CCB_WAITING: 669 /* Caller will release the CCB */ 670 wakeup(&done_ccb->ccb_h.cbfcnp); 671 return; 672 } 673 xpt_release_ccb(done_ccb); 674 } 675 676 static int 677 pterror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 678 { 679 struct pt_softc *softc; 680 struct cam_periph *periph; 681 682 periph = xpt_path_periph(ccb->ccb_h.path); 683 softc = (struct pt_softc *)periph->softc; 684 685 return(cam_periph_error(ccb, cam_flags, sense_flags, 686 &softc->saved_ccb)); 687 } 688 689 static int 690 ptioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 691 { 692 struct cam_periph *periph; 693 struct pt_softc *softc; 694 int unit; 695 int error; 696 697 unit = minor(dev); 698 periph = cam_extend_get(ptperiphs, unit); 699 700 if (periph == NULL) 701 return(ENXIO); 702 703 softc = (struct pt_softc *)periph->softc; 704 705 if ((error = cam_periph_lock(periph, PCATCH)) != 0) { 706 return (error); /* error code from tsleep */ 707 } 708 709 switch(cmd) { 710 case PTIOCGETTIMEOUT: 711 if (softc->io_timeout >= 1000) 712 *(int *)addr = softc->io_timeout / 1000; 713 else 714 *(int *)addr = 0; 715 break; 716 case PTIOCSETTIMEOUT: 717 { 718 int s; 719 720 if (*(int *)addr < 1) { 721 error = EINVAL; 722 break; 723 } 724 725 s = splsoftcam(); 726 softc->io_timeout = *(int *)addr * 1000; 727 splx(s); 728 729 break; 730 } 731 default: 732 error = cam_periph_ioctl(periph, cmd, addr, pterror); 733 break; 734 } 735 736 cam_periph_unlock(periph); 737 738 return(error); 739 } 740 741 void 742 scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries, 743 void (*cbfcnp)(struct cam_periph *, union ccb *), 744 u_int tag_action, int readop, u_int byte2, 745 u_int32_t xfer_len, u_int8_t *data_ptr, u_int8_t sense_len, 746 u_int32_t timeout) 747 { 748 struct scsi_send_receive *scsi_cmd; 749 750 scsi_cmd = (struct scsi_send_receive *)&csio->cdb_io.cdb_bytes; 751 scsi_cmd->opcode = readop ? RECEIVE : SEND; 752 scsi_cmd->byte2 = byte2; 753 scsi_ulto3b(xfer_len, scsi_cmd->xfer_len); 754 scsi_cmd->control = 0; 755 756 cam_fill_csio(csio, 757 retries, 758 cbfcnp, 759 /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT, 760 tag_action, 761 data_ptr, 762 xfer_len, 763 sense_len, 764 sizeof(*scsi_cmd), 765 timeout); 766 } 767