scsi_pass.c revision 260387
135069Speter/*- 2158502Speter * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs. 335069Speter * Copyright (c) 1997, 1998, 1999 Kenneth D. Merry. 435069Speter * All rights reserved. 535069Speter * 635069Speter * Redistribution and use in source and binary forms, with or without 735069Speter * modification, are permitted provided that the following conditions 835069Speter * are met: 935069Speter * 1. Redistributions of source code must retain the above copyright 1035069Speter * notice, this list of conditions, and the following disclaimer, 1135069Speter * without modification, immediately at the beginning of the file. 1235069Speter * 2. The name of the author may not be used to endorse or promote products 1335069Speter * derived from this software without specific prior written permission. 1435069Speter * 1535069Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1635069Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1735069Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1835069Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 1935069Speter * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2035069Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2135069Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2235069Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2335069Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2435069Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2535069Speter * SUCH DAMAGE. 2650477Speter */ 2735069Speter 2835069Speter#include <sys/cdefs.h> 2987702Sjhb__FBSDID("$FreeBSD: stable/10/sys/cam/scsi/scsi_pass.c 260387 2014-01-07 01:51:48Z scottl $"); 30166540Sbde 3165557Sjasone#include <sys/param.h> 32143063Sjoerg#include <sys/systm.h> 33166540Sbde#include <sys/kernel.h> 34143063Sjoerg#include <sys/types.h> 35143063Sjoerg#include <sys/bio.h> 3681763Sobrien#include <sys/malloc.h> 3781763Sobrien#include <sys/fcntl.h> 3865557Sjasone#include <sys/conf.h> 3965557Sjasone#include <sys/errno.h> 4065557Sjasone#include <sys/devicestat.h> 4135069Speter#include <sys/proc.h> 4235069Speter#include <sys/taskqueue.h> 4335069Speter 4435069Speter#include <cam/cam.h> 4535069Speter#include <cam/cam_ccb.h> 4635069Speter#include <cam/cam_periph.h> 4735069Speter#include <cam/cam_queue.h> 4887702Sjhb#include <cam/cam_xpt_periph.h> 49166540Sbde#include <cam/cam_debug.h> 50116926Speter#include <cam/cam_sim.h> 5187702Sjhb#include <cam/cam_compat.h> 5287702Sjhb 5387702Sjhb#include <cam/scsi/scsi_all.h> 54145034Speter#include <cam/scsi/scsi_pass.h> 5593264Sdillon 56166540Sbdetypedef enum { 57153726Sdavidxu PASS_FLAG_OPEN = 0x01, 58166540Sbde PASS_FLAG_LOCKED = 0x02, 5935069Speter PASS_FLAG_INVALID = 0x04, 60166540Sbde PASS_FLAG_INITIAL_PHYSPATH = 0x08 61166540Sbde} pass_flags; 62104291Sphk 63104291Sphktypedef enum { 64166540Sbde PASS_STATE_NORMAL 65170291Sattilio} pass_state; 66170291Sattilio 67166540Sbdetypedef enum { 68166540Sbde PASS_CCB_BUFFER_IO 69166540Sbde} pass_ccb_types; 70166540Sbde 71166540Sbde#define ccb_type ppriv_field0 7287702Sjhb#define ccb_bp ppriv_ptr1 7387702Sjhb 7487702Sjhbstruct pass_softc { 7587702Sjhb pass_state state; 7687702Sjhb pass_flags flags; 7787702Sjhb u_int8_t pd_type; 7887702Sjhb union ccb saved_ccb; 7987702Sjhb int open_count; 8087702Sjhb struct devstat *device_stats; 8187702Sjhb struct cdev *dev; 8287702Sjhb struct cdev *alias_dev; 8387702Sjhb struct task add_physpath_task; 8487702Sjhb}; 8587702Sjhb 8687702Sjhb 87122833Sbdestatic d_open_t passopen; 8887702Sjhbstatic d_close_t passclose; 8987702Sjhbstatic d_ioctl_t passioctl; 9087702Sjhbstatic d_ioctl_t passdoioctl; 9187702Sjhb 9287702Sjhbstatic periph_init_t passinit; 9387702Sjhbstatic periph_ctor_t passregister; 9487702Sjhbstatic periph_oninv_t passoninvalidate; 9587702Sjhbstatic periph_dtor_t passcleanup; 9687702Sjhbstatic void pass_add_physpath(void *context, int pending); 9787702Sjhbstatic void passasync(void *callback_arg, u_int32_t code, 9887702Sjhb struct cam_path *path, void *arg); 9987702Sjhbstatic int passerror(union ccb *ccb, u_int32_t cam_flags, 10087702Sjhb u_int32_t sense_flags); 101122833Sbdestatic int passsendccb(struct cam_periph *periph, union ccb *ccb, 102166540Sbde union ccb *inccb); 103166540Sbde 104166540Sbdestatic struct periph_driver passdriver = 105166540Sbde{ 10687702Sjhb passinit, "pass", 107166540Sbde TAILQ_HEAD_INITIALIZER(passdriver.units), /* generation */ 0 108166540Sbde}; 109166536Sbde 110166536SbdePERIPHDRIVER_DECLARE(pass, passdriver); 111166536Sbde 112166540Sbdestatic struct cdevsw pass_cdevsw = { 11387702Sjhb .d_version = D_VERSION, 114166540Sbde .d_flags = D_TRACKCLOSE, 11587702Sjhb .d_open = passopen, 116166540Sbde .d_close = passclose, 11787702Sjhb .d_ioctl = passioctl, 11887702Sjhb .d_name = "pass", 11987702Sjhb}; 120170291Sattilio 121170291Sattiliostatic void 122170291Sattiliopassinit(void) 123170291Sattilio{ 124170291Sattilio cam_status status; 125170291Sattilio 126170291Sattilio /* 127170291Sattilio * Install a global async callback. This callback will 128170291Sattilio * receive async callbacks like "new device found". 129170291Sattilio */ 130170291Sattilio status = xpt_register_async(AC_FOUND_DEVICE, passasync, NULL, NULL); 131170291Sattilio 132170291Sattilio if (status != CAM_REQ_CMP) { 133170291Sattilio printf("pass: Failed to attach master async callback " 134170291Sattilio "due to status 0x%x!\n", status); 135170291Sattilio } 136170291Sattilio 137170291Sattilio} 138170291Sattilio 139170291Sattiliostatic void 140170291Sattiliopassdevgonecb(void *arg) 141167429Salc{ 142167429Salc struct cam_periph *periph; 143167429Salc struct mtx *mtx; 144170291Sattilio struct pass_softc *softc; 145167429Salc int i; 146167429Salc 147167429Salc periph = (struct cam_periph *)arg; 148167429Salc mtx = cam_periph_mtx(periph); 149167429Salc mtx_lock(mtx); 150167429Salc 151167429Salc softc = (struct pass_softc *)periph->softc; 152167429Salc KASSERT(softc->open_count >= 0, ("Negative open count %d", 153167429Salc softc->open_count)); 154167429Salc 155167429Salc /* 156167429Salc * When we get this callback, we will get no more close calls from 157167429Salc * devfs. So if we have any dangling opens, we need to release the 158167429Salc * reference held for that particular context. 159167429Salc */ 160167429Salc for (i = 0; i < softc->open_count; i++) 161167429Salc cam_periph_release_locked(periph); 162167429Salc 163167429Salc softc->open_count = 0; 16487702Sjhb 16587702Sjhb /* 166122833Sbde * Release the reference held for the device node, it is gone now. 167166540Sbde */ 168166540Sbde cam_periph_release_locked(periph); 169166540Sbde 170166540Sbde /* 17187702Sjhb * We reference the lock directly here, instead of using 172166540Sbde * cam_periph_unlock(). The reason is that the final call to 173166536Sbde * cam_periph_release_locked() above could result in the periph 174166536Sbde * getting freed. If that is the case, dereferencing the periph 175166536Sbde * with a cam_periph_unlock() call would cause a page fault. 176166536Sbde */ 177166536Sbde mtx_unlock(mtx); 178166536Sbde} 17987702Sjhb 18087702Sjhbstatic void 18187702Sjhbpassoninvalidate(struct cam_periph *periph) 182122833Sbde{ 18387702Sjhb struct pass_softc *softc; 18487702Sjhb 185170291Sattilio softc = (struct pass_softc *)periph->softc; 186170291Sattilio 18787702Sjhb /* 18887702Sjhb * De-register any async callbacks. 18987702Sjhb */ 190122931Speter xpt_register_async(0, passasync, periph, periph->path); 191122931Speter 192122931Speter softc->flags |= PASS_FLAG_INVALID; 193122931Speter 194122931Speter /* 195122931Speter * Tell devfs this device has gone away, and ask for a callback 196122931Speter * when it has cleaned up its state. 197122931Speter */ 198166540Sbde destroy_dev_sched_cb(softc->dev, passdevgonecb, periph); 199122931Speter 200166540Sbde /* 201100079Smarkm * XXX Return all queued I/O with ENXIO. 202166540Sbde * XXX Handle any transactions queued to the card 20381763Sobrien * with XPT_ABORT_CCB. 204166540Sbde */ 205166540Sbde} 206166540Sbde 207166540Sbdestatic void 208166540Sbdepasscleanup(struct cam_periph *periph) 209{ 210 struct pass_softc *softc; 211 212 softc = (struct pass_softc *)periph->softc; 213 214 devstat_remove_entry(softc->device_stats); 215 216 cam_periph_unlock(periph); 217 taskqueue_drain(taskqueue_thread, &softc->add_physpath_task); 218 219 cam_periph_lock(periph); 220 221 free(softc, M_DEVBUF); 222} 223 224static void 225pass_add_physpath(void *context, int pending) 226{ 227 struct cam_periph *periph; 228 struct pass_softc *softc; 229 char *physpath; 230 231 /* 232 * If we have one, create a devfs alias for our 233 * physical path. 234 */ 235 periph = context; 236 softc = periph->softc; 237 physpath = malloc(MAXPATHLEN, M_DEVBUF, M_WAITOK); 238 cam_periph_lock(periph); 239 if (periph->flags & CAM_PERIPH_INVALID) { 240 cam_periph_unlock(periph); 241 goto out; 242 } 243 if (xpt_getattr(physpath, MAXPATHLEN, 244 "GEOM::physpath", periph->path) == 0 245 && strlen(physpath) != 0) { 246 247 cam_periph_unlock(periph); 248 make_dev_physpath_alias(MAKEDEV_WAITOK, &softc->alias_dev, 249 softc->dev, softc->alias_dev, physpath); 250 cam_periph_lock(periph); 251 } 252 253 /* 254 * Now that we've made our alias, we no longer have to have a 255 * reference to the device. 256 */ 257 if ((softc->flags & PASS_FLAG_INITIAL_PHYSPATH) == 0) { 258 softc->flags |= PASS_FLAG_INITIAL_PHYSPATH; 259 cam_periph_unlock(periph); 260 dev_rel(softc->dev); 261 } 262 else 263 cam_periph_unlock(periph); 264 265out: 266 free(physpath, M_DEVBUF); 267} 268 269static void 270passasync(void *callback_arg, u_int32_t code, 271 struct cam_path *path, void *arg) 272{ 273 struct cam_periph *periph; 274 275 periph = (struct cam_periph *)callback_arg; 276 277 switch (code) { 278 case AC_FOUND_DEVICE: 279 { 280 struct ccb_getdev *cgd; 281 cam_status status; 282 283 cgd = (struct ccb_getdev *)arg; 284 if (cgd == NULL) 285 break; 286 287 /* 288 * Allocate a peripheral instance for 289 * this device and start the probe 290 * process. 291 */ 292 status = cam_periph_alloc(passregister, passoninvalidate, 293 passcleanup, NULL, "pass", 294 CAM_PERIPH_BIO, path, 295 passasync, AC_FOUND_DEVICE, cgd); 296 297 if (status != CAM_REQ_CMP 298 && status != CAM_REQ_INPROG) { 299 const struct cam_status_entry *entry; 300 301 entry = cam_fetch_status_entry(status); 302 303 printf("passasync: Unable to attach new device " 304 "due to status %#x: %s\n", status, entry ? 305 entry->status_text : "Unknown"); 306 } 307 308 break; 309 } 310 case AC_ADVINFO_CHANGED: 311 { 312 uintptr_t buftype; 313 314 buftype = (uintptr_t)arg; 315 if (buftype == CDAI_TYPE_PHYS_PATH) { 316 struct pass_softc *softc; 317 318 softc = (struct pass_softc *)periph->softc; 319 taskqueue_enqueue(taskqueue_thread, 320 &softc->add_physpath_task); 321 } 322 break; 323 } 324 default: 325 cam_periph_async(periph, code, path, arg); 326 break; 327 } 328} 329 330static cam_status 331passregister(struct cam_periph *periph, void *arg) 332{ 333 struct pass_softc *softc; 334 struct ccb_getdev *cgd; 335 struct ccb_pathinq cpi; 336 int no_tags; 337 338 cgd = (struct ccb_getdev *)arg; 339 if (cgd == NULL) { 340 printf("%s: no getdev CCB, can't register device\n", __func__); 341 return(CAM_REQ_CMP_ERR); 342 } 343 344 softc = (struct pass_softc *)malloc(sizeof(*softc), 345 M_DEVBUF, M_NOWAIT); 346 347 if (softc == NULL) { 348 printf("%s: Unable to probe new device. " 349 "Unable to allocate softc\n", __func__); 350 return(CAM_REQ_CMP_ERR); 351 } 352 353 bzero(softc, sizeof(*softc)); 354 softc->state = PASS_STATE_NORMAL; 355 if (cgd->protocol == PROTO_SCSI || cgd->protocol == PROTO_ATAPI) 356 softc->pd_type = SID_TYPE(&cgd->inq_data); 357 else if (cgd->protocol == PROTO_SATAPM) 358 softc->pd_type = T_ENCLOSURE; 359 else 360 softc->pd_type = T_DIRECT; 361 362 periph->softc = softc; 363 364 bzero(&cpi, sizeof(cpi)); 365 xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 366 cpi.ccb_h.func_code = XPT_PATH_INQ; 367 xpt_action((union ccb *)&cpi); 368 369 /* 370 * We pass in 0 for a blocksize, since we don't 371 * know what the blocksize of this device is, if 372 * it even has a blocksize. 373 */ 374 cam_periph_unlock(periph); 375 no_tags = (cgd->inq_data.flags & SID_CmdQue) == 0; 376 softc->device_stats = devstat_new_entry("pass", 377 periph->unit_number, 0, 378 DEVSTAT_NO_BLOCKSIZE 379 | (no_tags ? DEVSTAT_NO_ORDERED_TAGS : 0), 380 softc->pd_type | 381 XPORT_DEVSTAT_TYPE(cpi.transport) | 382 DEVSTAT_TYPE_PASS, 383 DEVSTAT_PRIORITY_PASS); 384 385 /* 386 * Acquire a reference to the periph before we create the devfs 387 * instance for it. We'll release this reference once the devfs 388 * instance has been freed. 389 */ 390 if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 391 xpt_print(periph->path, "%s: lost periph during " 392 "registration!\n", __func__); 393 cam_periph_lock(periph); 394 return (CAM_REQ_CMP_ERR); 395 } 396 397 /* Register the device */ 398 softc->dev = make_dev(&pass_cdevsw, periph->unit_number, 399 UID_ROOT, GID_OPERATOR, 0600, "%s%d", 400 periph->periph_name, periph->unit_number); 401 402 /* 403 * Now that we have made the devfs instance, hold a reference to it 404 * until the task queue has run to setup the physical path alias. 405 * That way devfs won't get rid of the device before we add our 406 * alias. 407 */ 408 dev_ref(softc->dev); 409 410 cam_periph_lock(periph); 411 softc->dev->si_drv1 = periph; 412 413 TASK_INIT(&softc->add_physpath_task, /*priority*/0, 414 pass_add_physpath, periph); 415 416 /* 417 * See if physical path information is already available. 418 */ 419 taskqueue_enqueue(taskqueue_thread, &softc->add_physpath_task); 420 421 /* 422 * Add an async callback so that we get notified if 423 * this device goes away or its physical path 424 * (stored in the advanced info data of the EDT) has 425 * changed. 426 */ 427 xpt_register_async(AC_LOST_DEVICE | AC_ADVINFO_CHANGED, 428 passasync, periph, periph->path); 429 430 if (bootverbose) 431 xpt_announce_periph(periph, NULL); 432 433 return(CAM_REQ_CMP); 434} 435 436static int 437passopen(struct cdev *dev, int flags, int fmt, struct thread *td) 438{ 439 struct cam_periph *periph; 440 struct pass_softc *softc; 441 int error; 442 443 periph = (struct cam_periph *)dev->si_drv1; 444 if (cam_periph_acquire(periph) != CAM_REQ_CMP) 445 return (ENXIO); 446 447 cam_periph_lock(periph); 448 449 softc = (struct pass_softc *)periph->softc; 450 451 if (softc->flags & PASS_FLAG_INVALID) { 452 cam_periph_release_locked(periph); 453 cam_periph_unlock(periph); 454 return(ENXIO); 455 } 456 457 /* 458 * Don't allow access when we're running at a high securelevel. 459 */ 460 error = securelevel_gt(td->td_ucred, 1); 461 if (error) { 462 cam_periph_release_locked(periph); 463 cam_periph_unlock(periph); 464 return(error); 465 } 466 467 /* 468 * Only allow read-write access. 469 */ 470 if (((flags & FWRITE) == 0) || ((flags & FREAD) == 0)) { 471 cam_periph_release_locked(periph); 472 cam_periph_unlock(periph); 473 return(EPERM); 474 } 475 476 /* 477 * We don't allow nonblocking access. 478 */ 479 if ((flags & O_NONBLOCK) != 0) { 480 xpt_print(periph->path, "can't do nonblocking access\n"); 481 cam_periph_release_locked(periph); 482 cam_periph_unlock(periph); 483 return(EINVAL); 484 } 485 486 softc->open_count++; 487 488 cam_periph_unlock(periph); 489 490 return (error); 491} 492 493static int 494passclose(struct cdev *dev, int flag, int fmt, struct thread *td) 495{ 496 struct cam_periph *periph; 497 struct pass_softc *softc; 498 struct mtx *mtx; 499 500 periph = (struct cam_periph *)dev->si_drv1; 501 if (periph == NULL) 502 return (ENXIO); 503 mtx = cam_periph_mtx(periph); 504 mtx_lock(mtx); 505 506 softc = periph->softc; 507 softc->open_count--; 508 509 cam_periph_release_locked(periph); 510 511 /* 512 * We reference the lock directly here, instead of using 513 * cam_periph_unlock(). The reason is that the call to 514 * cam_periph_release_locked() above could result in the periph 515 * getting freed. If that is the case, dereferencing the periph 516 * with a cam_periph_unlock() call would cause a page fault. 517 * 518 * cam_periph_release() avoids this problem using the same method, 519 * but we're manually acquiring and dropping the lock here to 520 * protect the open count and avoid another lock acquisition and 521 * release. 522 */ 523 mtx_unlock(mtx); 524 525 return (0); 526} 527 528static int 529passioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 530{ 531 int error; 532 533 if ((error = passdoioctl(dev, cmd, addr, flag, td)) == ENOTTY) { 534 error = cam_compat_ioctl(dev, cmd, addr, flag, td, passdoioctl); 535 } 536 return (error); 537} 538 539static int 540passdoioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 541{ 542 struct cam_periph *periph; 543 struct pass_softc *softc; 544 int error; 545 uint32_t priority; 546 547 periph = (struct cam_periph *)dev->si_drv1; 548 if (periph == NULL) 549 return(ENXIO); 550 551 cam_periph_lock(periph); 552 softc = (struct pass_softc *)periph->softc; 553 554 error = 0; 555 556 switch (cmd) { 557 558 case CAMIOCOMMAND: 559 { 560 union ccb *inccb; 561 union ccb *ccb; 562 int ccb_malloced; 563 564 inccb = (union ccb *)addr; 565 566 /* 567 * Some CCB types, like scan bus and scan lun can only go 568 * through the transport layer device. 569 */ 570 if (inccb->ccb_h.func_code & XPT_FC_XPT_ONLY) { 571 xpt_print(periph->path, "CCB function code %#x is " 572 "restricted to the XPT device\n", 573 inccb->ccb_h.func_code); 574 error = ENODEV; 575 break; 576 } 577 578 /* Compatibility for RL/priority-unaware code. */ 579 priority = inccb->ccb_h.pinfo.priority; 580 if (priority <= CAM_PRIORITY_OOB) 581 priority += CAM_PRIORITY_OOB + 1; 582 583 /* 584 * Non-immediate CCBs need a CCB from the per-device pool 585 * of CCBs, which is scheduled by the transport layer. 586 * Immediate CCBs and user-supplied CCBs should just be 587 * malloced. 588 */ 589 if ((inccb->ccb_h.func_code & XPT_FC_QUEUED) 590 && ((inccb->ccb_h.func_code & XPT_FC_USER_CCB) == 0)) { 591 ccb = cam_periph_getccb(periph, priority); 592 ccb_malloced = 0; 593 } else { 594 ccb = xpt_alloc_ccb_nowait(); 595 596 if (ccb != NULL) 597 xpt_setup_ccb(&ccb->ccb_h, periph->path, 598 priority); 599 ccb_malloced = 1; 600 } 601 602 if (ccb == NULL) { 603 xpt_print(periph->path, "unable to allocate CCB\n"); 604 error = ENOMEM; 605 break; 606 } 607 608 error = passsendccb(periph, ccb, inccb); 609 610 if (ccb_malloced) 611 xpt_free_ccb(ccb); 612 else 613 xpt_release_ccb(ccb); 614 615 break; 616 } 617 default: 618 error = cam_periph_ioctl(periph, cmd, addr, passerror); 619 break; 620 } 621 622 cam_periph_unlock(periph); 623 return(error); 624} 625 626/* 627 * Generally, "ccb" should be the CCB supplied by the kernel. "inccb" 628 * should be the CCB that is copied in from the user. 629 */ 630static int 631passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb) 632{ 633 struct pass_softc *softc; 634 struct cam_periph_map_info mapinfo; 635 xpt_opcode fc; 636 int error; 637 638 softc = (struct pass_softc *)periph->softc; 639 640 /* 641 * There are some fields in the CCB header that need to be 642 * preserved, the rest we get from the user. 643 */ 644 xpt_merge_ccb(ccb, inccb); 645 646 /* 647 * Let cam_periph_mapmem do a sanity check on the data pointer format. 648 * Even if no data transfer is needed, it's a cheap check and it 649 * simplifies the code. 650 */ 651 fc = ccb->ccb_h.func_code; 652 if ((fc == XPT_SCSI_IO) || (fc == XPT_ATA_IO) || (fc == XPT_SMP_IO) 653 || (fc == XPT_DEV_MATCH) || (fc == XPT_DEV_ADVINFO)) { 654 bzero(&mapinfo, sizeof(mapinfo)); 655 656 /* 657 * cam_periph_mapmem calls into proc and vm functions that can 658 * sleep as well as trigger I/O, so we can't hold the lock. 659 * Dropping it here is reasonably safe. 660 */ 661 cam_periph_unlock(periph); 662 error = cam_periph_mapmem(ccb, &mapinfo); 663 cam_periph_lock(periph); 664 665 /* 666 * cam_periph_mapmem returned an error, we can't continue. 667 * Return the error to the user. 668 */ 669 if (error) 670 return(error); 671 } else 672 /* Ensure that the unmap call later on is a no-op. */ 673 mapinfo.num_bufs_used = 0; 674 675 /* 676 * If the user wants us to perform any error recovery, then honor 677 * that request. Otherwise, it's up to the user to perform any 678 * error recovery. 679 */ 680 cam_periph_runccb(ccb, passerror, /* cam_flags */ CAM_RETRY_SELTO, 681 /* sense_flags */ ((ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ? 682 SF_RETRY_UA : SF_NO_RECOVERY) | SF_NO_PRINT, 683 softc->device_stats); 684 685 cam_periph_unmapmem(ccb, &mapinfo); 686 687 ccb->ccb_h.cbfcnp = NULL; 688 ccb->ccb_h.periph_priv = inccb->ccb_h.periph_priv; 689 bcopy(ccb, inccb, sizeof(union ccb)); 690 691 return(0); 692} 693 694static int 695passerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 696{ 697 struct cam_periph *periph; 698 struct pass_softc *softc; 699 700 periph = xpt_path_periph(ccb->ccb_h.path); 701 softc = (struct pass_softc *)periph->softc; 702 703 return(cam_periph_error(ccb, cam_flags, sense_flags, 704 &softc->saved_ccb)); 705} 706