1 /* 2 * Copyright (c) 1997, 1998 Justin T. Gibbs. 3 * Copyright (c) 1997, 1998, 1999 Kenneth D. Merry. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions, and the following disclaimer, 11 * without modification, immediately at the beginning of the file. 12 * 2. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 19 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD: src/sys/cam/scsi/scsi_pass.c,v 1.19 2000/01/17 06:27:37 mjacob Exp $ 28 * $DragonFly: src/sys/bus/cam/scsi/scsi_pass.c,v 1.12 2004/05/19 22:52:38 dillon Exp $ 29 */ 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/kernel.h> 34 #include <sys/types.h> 35 #include <sys/buf.h> 36 #include <sys/malloc.h> 37 #include <sys/fcntl.h> 38 #include <sys/stat.h> 39 #include <sys/conf.h> 40 #include <sys/buf.h> 41 #include <sys/proc.h> 42 #include <sys/errno.h> 43 #include <sys/devicestat.h> 44 #include <sys/proc.h> 45 #include <sys/buf2.h> 46 47 #include "../cam.h" 48 #include "../cam_ccb.h" 49 #include "../cam_extend.h" 50 #include "../cam_periph.h" 51 #include "../cam_xpt_periph.h" 52 #include "../cam_debug.h" 53 54 #include "scsi_all.h" 55 #include "scsi_message.h" 56 #include "scsi_da.h" 57 #include "scsi_pass.h" 58 59 typedef enum { 60 PASS_FLAG_OPEN = 0x01, 61 PASS_FLAG_LOCKED = 0x02, 62 PASS_FLAG_INVALID = 0x04 63 } pass_flags; 64 65 typedef enum { 66 PASS_STATE_NORMAL 67 } pass_state; 68 69 typedef enum { 70 PASS_CCB_BUFFER_IO, 71 PASS_CCB_WAITING 72 } pass_ccb_types; 73 74 #define ccb_type ppriv_field0 75 #define ccb_bp ppriv_ptr1 76 77 struct pass_softc { 78 pass_state state; 79 pass_flags flags; 80 u_int8_t pd_type; 81 struct buf_queue_head buf_queue; 82 union ccb saved_ccb; 83 struct devstat device_stats; 84 }; 85 86 #define PASS_CDEV_MAJOR 31 87 88 static d_open_t passopen; 89 static d_close_t passclose; 90 static d_ioctl_t passioctl; 91 static d_strategy_t passstrategy; 92 93 static periph_init_t passinit; 94 static periph_ctor_t passregister; 95 static periph_oninv_t passoninvalidate; 96 static periph_dtor_t passcleanup; 97 static periph_start_t passstart; 98 static void passasync(void *callback_arg, u_int32_t code, 99 struct cam_path *path, void *arg); 100 static void passdone(struct cam_periph *periph, 101 union ccb *done_ccb); 102 static int passerror(union ccb *ccb, u_int32_t cam_flags, 103 u_int32_t sense_flags); 104 static int passsendccb(struct cam_periph *periph, union ccb *ccb, 105 union ccb *inccb); 106 107 static struct periph_driver passdriver = 108 { 109 passinit, "pass", 110 TAILQ_HEAD_INITIALIZER(passdriver.units), /* generation */ 0 111 }; 112 113 DATA_SET(periphdriver_set, passdriver); 114 115 static struct cdevsw pass_cdevsw = { 116 /* name */ "pass", 117 /* maj */ PASS_CDEV_MAJOR, 118 /* flags */ 0, 119 /* port */ NULL, 120 /* clone */ NULL, 121 122 /* open */ passopen, 123 /* close */ passclose, 124 /* read */ physread, 125 /* write */ physwrite, 126 /* ioctl */ passioctl, 127 /* poll */ nopoll, 128 /* mmap */ nommap, 129 /* strategy */ passstrategy, 130 /* dump */ nodump, 131 /* psize */ nopsize 132 }; 133 134 static struct extend_array *passperiphs; 135 136 static void 137 passinit(void) 138 { 139 cam_status status; 140 struct cam_path *path; 141 142 /* 143 * Create our extend array for storing the devices we attach to. 144 */ 145 passperiphs = cam_extend_new(); 146 if (passperiphs == NULL) { 147 printf("passm: Failed to alloc extend array!\n"); 148 return; 149 } 150 151 /* 152 * Install a global async callback. This callback will 153 * receive async callbacks like "new device found". 154 */ 155 status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, 156 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 157 158 if (status == CAM_REQ_CMP) { 159 struct ccb_setasync csa; 160 161 xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); 162 csa.ccb_h.func_code = XPT_SASYNC_CB; 163 csa.event_enable = AC_FOUND_DEVICE; 164 csa.callback = passasync; 165 csa.callback_arg = NULL; 166 xpt_action((union ccb *)&csa); 167 status = csa.ccb_h.status; 168 xpt_free_path(path); 169 } 170 171 if (status != CAM_REQ_CMP) { 172 printf("pass: Failed to attach master async callback " 173 "due to status 0x%x!\n", status); 174 } 175 176 } 177 178 static void 179 passoninvalidate(struct cam_periph *periph) 180 { 181 int s; 182 struct pass_softc *softc; 183 struct buf *q_bp; 184 struct ccb_setasync csa; 185 186 softc = (struct pass_softc *)periph->softc; 187 188 /* 189 * De-register any async callbacks. 190 */ 191 xpt_setup_ccb(&csa.ccb_h, periph->path, 192 /* priority */ 5); 193 csa.ccb_h.func_code = XPT_SASYNC_CB; 194 csa.event_enable = 0; 195 csa.callback = passasync; 196 csa.callback_arg = periph; 197 xpt_action((union ccb *)&csa); 198 199 softc->flags |= PASS_FLAG_INVALID; 200 201 /* 202 * Although the oninvalidate() routines are always called at 203 * splsoftcam, we need to be at splbio() here to keep the buffer 204 * queue from being modified while we traverse it. 205 */ 206 s = splbio(); 207 208 /* 209 * Return all queued I/O with ENXIO. 210 * XXX Handle any transactions queued to the card 211 * with XPT_ABORT_CCB. 212 */ 213 while ((q_bp = bufq_first(&softc->buf_queue)) != NULL){ 214 bufq_remove(&softc->buf_queue, q_bp); 215 q_bp->b_resid = q_bp->b_bcount; 216 q_bp->b_error = ENXIO; 217 q_bp->b_flags |= B_ERROR; 218 biodone(q_bp); 219 } 220 splx(s); 221 222 if (bootverbose) { 223 xpt_print_path(periph->path); 224 printf("lost device\n"); 225 } 226 227 } 228 229 static void 230 passcleanup(struct cam_periph *periph) 231 { 232 struct pass_softc *softc; 233 234 softc = (struct pass_softc *)periph->softc; 235 236 devstat_remove_entry(&softc->device_stats); 237 238 cam_extend_release(passperiphs, periph->unit_number); 239 240 if (bootverbose) { 241 xpt_print_path(periph->path); 242 printf("removing device entry\n"); 243 } 244 cdevsw_remove(&pass_cdevsw, -1, periph->unit_number); 245 free(softc, M_DEVBUF); 246 } 247 248 static void 249 passasync(void *callback_arg, u_int32_t code, 250 struct cam_path *path, void *arg) 251 { 252 struct cam_periph *periph; 253 254 periph = (struct cam_periph *)callback_arg; 255 256 switch (code) { 257 case AC_FOUND_DEVICE: 258 { 259 struct ccb_getdev *cgd; 260 cam_status status; 261 262 cgd = (struct ccb_getdev *)arg; 263 264 /* 265 * Allocate a peripheral instance for 266 * this device and start the probe 267 * process. 268 */ 269 status = cam_periph_alloc(passregister, passoninvalidate, 270 passcleanup, passstart, "pass", 271 CAM_PERIPH_BIO, cgd->ccb_h.path, 272 passasync, AC_FOUND_DEVICE, cgd); 273 274 if (status != CAM_REQ_CMP 275 && status != CAM_REQ_INPROG) 276 printf("passasync: Unable to attach new device " 277 "due to status 0x%x\n", status); 278 279 break; 280 } 281 default: 282 cam_periph_async(periph, code, path, arg); 283 break; 284 } 285 } 286 287 static cam_status 288 passregister(struct cam_periph *periph, void *arg) 289 { 290 struct pass_softc *softc; 291 struct ccb_setasync csa; 292 struct ccb_getdev *cgd; 293 294 cgd = (struct ccb_getdev *)arg; 295 if (periph == NULL) { 296 printf("passregister: periph was NULL!!\n"); 297 return(CAM_REQ_CMP_ERR); 298 } 299 300 if (cgd == NULL) { 301 printf("passregister: no getdev CCB, can't register device\n"); 302 return(CAM_REQ_CMP_ERR); 303 } 304 305 softc = malloc(sizeof(*softc), M_DEVBUF, M_INTWAIT | M_ZERO); 306 softc->state = PASS_STATE_NORMAL; 307 softc->pd_type = SID_TYPE(&cgd->inq_data); 308 bufq_init(&softc->buf_queue); 309 310 periph->softc = softc; 311 312 cam_extend_set(passperiphs, periph->unit_number, periph); 313 /* 314 * We pass in 0 for a blocksize, since we don't 315 * know what the blocksize of this device is, if 316 * it even has a blocksize. 317 */ 318 devstat_add_entry(&softc->device_stats, "pass", periph->unit_number, 319 0, DEVSTAT_NO_BLOCKSIZE | DEVSTAT_NO_ORDERED_TAGS, 320 softc->pd_type | 321 DEVSTAT_TYPE_IF_SCSI | 322 DEVSTAT_TYPE_PASS, 323 DEVSTAT_PRIORITY_PASS); 324 325 /* Register the device */ 326 cdevsw_add(&pass_cdevsw, -1, periph->unit_number); 327 make_dev(&pass_cdevsw, periph->unit_number, UID_ROOT, 328 GID_OPERATOR, 0600, "%s%d", periph->periph_name, 329 periph->unit_number); 330 331 /* 332 * Add an async callback so that we get 333 * notified if this device goes away. 334 */ 335 xpt_setup_ccb(&csa.ccb_h, periph->path, /* priority */ 5); 336 csa.ccb_h.func_code = XPT_SASYNC_CB; 337 csa.event_enable = AC_LOST_DEVICE; 338 csa.callback = passasync; 339 csa.callback_arg = periph; 340 xpt_action((union ccb *)&csa); 341 342 if (bootverbose) 343 xpt_announce_periph(periph, NULL); 344 345 return(CAM_REQ_CMP); 346 } 347 348 static int 349 passopen(dev_t dev, int flags, int fmt, struct thread *td) 350 { 351 struct cam_periph *periph; 352 struct pass_softc *softc; 353 int unit, error; 354 int s; 355 356 error = 0; /* default to no error */ 357 358 /* unit = dkunit(dev); */ 359 /* XXX KDM fix this */ 360 unit = minor(dev) & 0xff; 361 362 periph = cam_extend_get(passperiphs, unit); 363 364 if (periph == NULL) 365 return (ENXIO); 366 367 softc = (struct pass_softc *)periph->softc; 368 369 s = splsoftcam(); 370 if (softc->flags & PASS_FLAG_INVALID) { 371 splx(s); 372 return(ENXIO); 373 } 374 375 /* 376 * Don't allow access when we're running at a high securelvel. 377 */ 378 if (securelevel > 1) { 379 splx(s); 380 return(EPERM); 381 } 382 383 /* 384 * Only allow read-write access. 385 */ 386 if (((flags & FWRITE) == 0) || ((flags & FREAD) == 0)) { 387 splx(s); 388 return(EPERM); 389 } 390 391 /* 392 * We don't allow nonblocking access. 393 */ 394 if ((flags & O_NONBLOCK) != 0) { 395 xpt_print_path(periph->path); 396 printf("can't do nonblocking accesss\n"); 397 splx(s); 398 return(EINVAL); 399 } 400 401 if ((error = cam_periph_lock(periph, PCATCH)) != 0) { 402 splx(s); 403 return (error); 404 } 405 406 splx(s); 407 408 if ((softc->flags & PASS_FLAG_OPEN) == 0) { 409 if (cam_periph_acquire(periph) != CAM_REQ_CMP) 410 return(ENXIO); 411 softc->flags |= PASS_FLAG_OPEN; 412 } 413 414 cam_periph_unlock(periph); 415 416 return (error); 417 } 418 419 static int 420 passclose(dev_t dev, int flag, int fmt, struct thread *td) 421 { 422 struct cam_periph *periph; 423 struct pass_softc *softc; 424 int unit, error; 425 426 /* unit = dkunit(dev); */ 427 /* XXX KDM fix this */ 428 unit = minor(dev) & 0xff; 429 430 periph = cam_extend_get(passperiphs, unit); 431 if (periph == NULL) 432 return (ENXIO); 433 434 softc = (struct pass_softc *)periph->softc; 435 436 if ((error = cam_periph_lock(periph, 0)) != 0) 437 return (error); 438 439 softc->flags &= ~PASS_FLAG_OPEN; 440 441 cam_periph_unlock(periph); 442 cam_periph_release(periph); 443 444 return (0); 445 } 446 447 /* 448 * Actually translate the requested transfer into one the physical driver 449 * can understand. The transfer is described by a buf and will include 450 * only one physical transfer. 451 */ 452 static void 453 passstrategy(struct buf *bp) 454 { 455 struct cam_periph *periph; 456 struct pass_softc *softc; 457 u_int unit; 458 int s; 459 460 /* 461 * The read/write interface for the passthrough driver doesn't 462 * really work right now. So, we just pass back EINVAL to tell the 463 * user to go away. 464 */ 465 bp->b_error = EINVAL; 466 goto bad; 467 468 /* unit = dkunit(bp->b_dev); */ 469 /* XXX KDM fix this */ 470 unit = minor(bp->b_dev) & 0xff; 471 472 periph = cam_extend_get(passperiphs, unit); 473 if (periph == NULL) { 474 bp->b_error = ENXIO; 475 goto bad; 476 } 477 softc = (struct pass_softc *)periph->softc; 478 479 /* 480 * Odd number of bytes or negative offset 481 */ 482 /* valid request? */ 483 if (bp->b_blkno < 0) { 484 bp->b_error = EINVAL; 485 goto bad; 486 } 487 488 /* 489 * Mask interrupts so that the pack cannot be invalidated until 490 * after we are in the queue. Otherwise, we might not properly 491 * clean up one of the buffers. 492 */ 493 s = splbio(); 494 495 bufq_insert_tail(&softc->buf_queue, bp); 496 497 splx(s); 498 499 /* 500 * Schedule ourselves for performing the work. 501 */ 502 xpt_schedule(periph, /* XXX priority */1); 503 504 return; 505 bad: 506 bp->b_flags |= B_ERROR; 507 508 /* 509 * Correctly set the buf to indicate a completed xfer 510 */ 511 bp->b_resid = bp->b_bcount; 512 biodone(bp); 513 return; 514 } 515 516 static void 517 passstart(struct cam_periph *periph, union ccb *start_ccb) 518 { 519 struct pass_softc *softc; 520 int s; 521 522 softc = (struct pass_softc *)periph->softc; 523 524 switch (softc->state) { 525 case PASS_STATE_NORMAL: 526 { 527 struct buf *bp; 528 529 s = splbio(); 530 bp = bufq_first(&softc->buf_queue); 531 if (periph->immediate_priority <= periph->pinfo.priority) { 532 start_ccb->ccb_h.ccb_type = PASS_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 543 bufq_remove(&softc->buf_queue, bp); 544 545 devstat_start_transaction(&softc->device_stats); 546 547 /* 548 * XXX JGibbs - 549 * Interpret the contents of the bp as a CCB 550 * and pass it to a routine shared by our ioctl 551 * code and passtart. 552 * For now, just biodone it with EIO so we don't 553 * hang. 554 */ 555 bp->b_error = EIO; 556 bp->b_flags |= B_ERROR; 557 bp->b_resid = bp->b_bcount; 558 biodone(bp); 559 bp = bufq_first(&softc->buf_queue); 560 splx(s); 561 562 xpt_action(start_ccb); 563 564 } 565 if (bp != NULL) { 566 /* Have more work to do, so ensure we stay scheduled */ 567 xpt_schedule(periph, /* XXX priority */1); 568 } 569 break; 570 } 571 } 572 } 573 static void 574 passdone(struct cam_periph *periph, union ccb *done_ccb) 575 { 576 struct pass_softc *softc; 577 struct ccb_scsiio *csio; 578 579 softc = (struct pass_softc *)periph->softc; 580 csio = &done_ccb->csio; 581 switch (csio->ccb_h.ccb_type) { 582 case PASS_CCB_BUFFER_IO: 583 { 584 struct buf *bp; 585 cam_status status; 586 u_int8_t scsi_status; 587 devstat_trans_flags ds_flags; 588 589 status = done_ccb->ccb_h.status; 590 scsi_status = done_ccb->csio.scsi_status; 591 bp = (struct buf *)done_ccb->ccb_h.ccb_bp; 592 /* XXX handle errors */ 593 if (!(((status & CAM_STATUS_MASK) == CAM_REQ_CMP) 594 && (scsi_status == SCSI_STATUS_OK))) { 595 int error; 596 597 if ((error = passerror(done_ccb, 0, 0)) == ERESTART) { 598 /* 599 * A retry was scheuled, so 600 * just return. 601 */ 602 return; 603 } 604 605 /* 606 * XXX unfreeze the queue after we complete 607 * the abort process 608 */ 609 bp->b_error = error; 610 bp->b_flags |= B_ERROR; 611 } 612 613 if ((done_ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 614 ds_flags = DEVSTAT_READ; 615 else if ((done_ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) 616 ds_flags = DEVSTAT_WRITE; 617 else 618 ds_flags = DEVSTAT_NO_DATA; 619 620 devstat_end_transaction_buf(&softc->device_stats, bp); 621 biodone(bp); 622 break; 623 } 624 case PASS_CCB_WAITING: 625 { 626 /* Caller will release the CCB */ 627 wakeup(&done_ccb->ccb_h.cbfcnp); 628 return; 629 } 630 } 631 xpt_release_ccb(done_ccb); 632 } 633 634 static int 635 passioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 636 { 637 struct cam_periph *periph; 638 struct pass_softc *softc; 639 u_int8_t unit; 640 int error; 641 642 643 /* unit = dkunit(dev); */ 644 /* XXX KDM fix this */ 645 unit = minor(dev) & 0xff; 646 647 periph = cam_extend_get(passperiphs, unit); 648 649 if (periph == NULL) 650 return(ENXIO); 651 652 softc = (struct pass_softc *)periph->softc; 653 654 error = 0; 655 656 switch (cmd) { 657 658 case CAMIOCOMMAND: 659 { 660 union ccb *inccb; 661 union ccb *ccb; 662 int ccb_malloced; 663 664 inccb = (union ccb *)addr; 665 666 /* 667 * Some CCB types, like scan bus and scan lun can only go 668 * through the transport layer device. 669 */ 670 if (inccb->ccb_h.func_code & XPT_FC_XPT_ONLY) { 671 xpt_print_path(periph->path); 672 printf("CCB function code %#x is restricted to the " 673 "XPT device\n", inccb->ccb_h.func_code); 674 error = ENODEV; 675 break; 676 } 677 678 /* 679 * Non-immediate CCBs need a CCB from the per-device pool 680 * of CCBs, which is scheduled by the transport layer. 681 * Immediate CCBs and user-supplied CCBs should just be 682 * malloced. 683 */ 684 if ((inccb->ccb_h.func_code & XPT_FC_QUEUED) 685 && ((inccb->ccb_h.func_code & XPT_FC_USER_CCB) == 0)) { 686 ccb = cam_periph_getccb(periph, 687 inccb->ccb_h.pinfo.priority); 688 ccb_malloced = 0; 689 } else { 690 ccb = xpt_alloc_ccb(); 691 692 if (ccb != NULL) 693 xpt_setup_ccb(&ccb->ccb_h, periph->path, 694 inccb->ccb_h.pinfo.priority); 695 ccb_malloced = 1; 696 } 697 698 if (ccb == NULL) { 699 xpt_print_path(periph->path); 700 printf("unable to allocate CCB\n"); 701 error = ENOMEM; 702 break; 703 } 704 705 error = passsendccb(periph, ccb, inccb); 706 707 if (ccb_malloced) 708 xpt_free_ccb(ccb); 709 else 710 xpt_release_ccb(ccb); 711 712 break; 713 } 714 default: 715 error = cam_periph_ioctl(periph, cmd, addr, passerror); 716 break; 717 } 718 719 return(error); 720 } 721 722 /* 723 * Generally, "ccb" should be the CCB supplied by the kernel. "inccb" 724 * should be the CCB that is copied in from the user. 725 */ 726 static int 727 passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb) 728 { 729 struct pass_softc *softc; 730 struct cam_periph_map_info mapinfo; 731 int error, need_unmap; 732 733 softc = (struct pass_softc *)periph->softc; 734 735 need_unmap = 0; 736 737 /* 738 * There are some fields in the CCB header that need to be 739 * preserved, the rest we get from the user. 740 */ 741 xpt_merge_ccb(ccb, inccb); 742 743 /* 744 * There's no way for the user to have a completion 745 * function, so we put our own completion function in here. 746 */ 747 ccb->ccb_h.cbfcnp = passdone; 748 749 /* 750 * We only attempt to map the user memory into kernel space 751 * if they haven't passed in a physical memory pointer, 752 * and if there is actually an I/O operation to perform. 753 * Right now cam_periph_mapmem() only supports SCSI and device 754 * match CCBs. For the SCSI CCBs, we only pass the CCB in if 755 * there's actually data to map. cam_periph_mapmem() will do the 756 * right thing, even if there isn't data to map, but since CCBs 757 * without data are a reasonably common occurance (e.g. test unit 758 * ready), it will save a few cycles if we check for it here. 759 */ 760 if (((ccb->ccb_h.flags & CAM_DATA_PHYS) == 0) 761 && (((ccb->ccb_h.func_code == XPT_SCSI_IO) 762 && ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)) 763 || (ccb->ccb_h.func_code == XPT_DEV_MATCH))) { 764 765 bzero(&mapinfo, sizeof(mapinfo)); 766 767 error = cam_periph_mapmem(ccb, &mapinfo); 768 769 /* 770 * cam_periph_mapmem returned an error, we can't continue. 771 * Return the error to the user. 772 */ 773 if (error) 774 return(error); 775 776 /* 777 * We successfully mapped the memory in, so we need to 778 * unmap it when the transaction is done. 779 */ 780 need_unmap = 1; 781 } 782 783 /* 784 * If the user wants us to perform any error recovery, then honor 785 * that request. Otherwise, it's up to the user to perform any 786 * error recovery. 787 */ 788 error = cam_periph_runccb(ccb, 789 (ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ? 790 passerror : NULL, 791 /* cam_flags */ 0, 792 /* sense_flags */SF_RETRY_UA | SF_RETRY_SELTO, 793 &softc->device_stats); 794 795 if (need_unmap != 0) 796 cam_periph_unmapmem(ccb, &mapinfo); 797 798 ccb->ccb_h.cbfcnp = NULL; 799 ccb->ccb_h.periph_priv = inccb->ccb_h.periph_priv; 800 bcopy(ccb, inccb, sizeof(union ccb)); 801 802 return(error); 803 } 804 805 static int 806 passerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 807 { 808 struct cam_periph *periph; 809 struct pass_softc *softc; 810 811 periph = xpt_path_periph(ccb->ccb_h.path); 812 softc = (struct pass_softc *)periph->softc; 813 814 return(cam_periph_error(ccb, cam_flags, sense_flags, 815 &softc->saved_ccb)); 816 } 817