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