xref: /freebsd/sys/cam/scsi/scsi_pass.c (revision 59e2ff550c448126b988150ce800cdf73bb5103e)
1 /*-
2  * Copyright (c) 1997, 1998, 2000 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 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/types.h>
35 #include <sys/bio.h>
36 #include <sys/malloc.h>
37 #include <sys/fcntl.h>
38 #include <sys/conf.h>
39 #include <sys/errno.h>
40 #include <sys/devicestat.h>
41 #include <sys/proc.h>
42 #include <sys/taskqueue.h>
43 
44 #include <cam/cam.h>
45 #include <cam/cam_ccb.h>
46 #include <cam/cam_periph.h>
47 #include <cam/cam_queue.h>
48 #include <cam/cam_xpt_periph.h>
49 #include <cam/cam_debug.h>
50 #include <cam/cam_sim.h>
51 #include <cam/cam_compat.h>
52 
53 #include <cam/scsi/scsi_all.h>
54 #include <cam/scsi/scsi_pass.h>
55 
56 typedef enum {
57 	PASS_FLAG_OPEN			= 0x01,
58 	PASS_FLAG_LOCKED		= 0x02,
59 	PASS_FLAG_INVALID		= 0x04,
60 	PASS_FLAG_INITIAL_PHYSPATH	= 0x08
61 } pass_flags;
62 
63 typedef enum {
64 	PASS_STATE_NORMAL
65 } pass_state;
66 
67 typedef enum {
68 	PASS_CCB_BUFFER_IO
69 } pass_ccb_types;
70 
71 #define ccb_type	ppriv_field0
72 #define ccb_bp		ppriv_ptr1
73 
74 struct pass_softc {
75 	pass_state	 state;
76 	pass_flags	 flags;
77 	u_int8_t	 pd_type;
78 	union ccb	 saved_ccb;
79 	int		 open_count;
80 	u_int		 maxio;
81 	struct devstat	*device_stats;
82 	struct cdev	*dev;
83 	struct cdev	*alias_dev;
84 	struct task	 add_physpath_task;
85 };
86 
87 
88 static	d_open_t	passopen;
89 static	d_close_t	passclose;
90 static	d_ioctl_t	passioctl;
91 static	d_ioctl_t	passdoioctl;
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 void		pass_add_physpath(void *context, int pending);
98 static	void		passasync(void *callback_arg, u_int32_t code,
99 				  struct cam_path *path, void *arg);
100 static	int		passerror(union ccb *ccb, u_int32_t cam_flags,
101 				  u_int32_t sense_flags);
102 static 	int		passsendccb(struct cam_periph *periph, union ccb *ccb,
103 				    union ccb *inccb);
104 
105 static struct periph_driver passdriver =
106 {
107 	passinit, "pass",
108 	TAILQ_HEAD_INITIALIZER(passdriver.units), /* generation */ 0
109 };
110 
111 PERIPHDRIVER_DECLARE(pass, passdriver);
112 
113 static struct cdevsw pass_cdevsw = {
114 	.d_version =	D_VERSION,
115 	.d_flags =	D_TRACKCLOSE,
116 	.d_open =	passopen,
117 	.d_close =	passclose,
118 	.d_ioctl =	passioctl,
119 	.d_name =	"pass",
120 };
121 
122 static void
123 passinit(void)
124 {
125 	cam_status status;
126 
127 	/*
128 	 * Install a global async callback.  This callback will
129 	 * receive async callbacks like "new device found".
130 	 */
131 	status = xpt_register_async(AC_FOUND_DEVICE, passasync, NULL, NULL);
132 
133 	if (status != CAM_REQ_CMP) {
134 		printf("pass: Failed to attach master async callback "
135 		       "due to status 0x%x!\n", status);
136 	}
137 
138 }
139 
140 static void
141 passdevgonecb(void *arg)
142 {
143 	struct cam_periph *periph;
144 	struct mtx *mtx;
145 	struct pass_softc *softc;
146 	int i;
147 
148 	periph = (struct cam_periph *)arg;
149 	mtx = cam_periph_mtx(periph);
150 	mtx_lock(mtx);
151 
152 	softc = (struct pass_softc *)periph->softc;
153 	KASSERT(softc->open_count >= 0, ("Negative open count %d",
154 		softc->open_count));
155 
156 	/*
157 	 * When we get this callback, we will get no more close calls from
158 	 * devfs.  So if we have any dangling opens, we need to release the
159 	 * reference held for that particular context.
160 	 */
161 	for (i = 0; i < softc->open_count; i++)
162 		cam_periph_release_locked(periph);
163 
164 	softc->open_count = 0;
165 
166 	/*
167 	 * Release the reference held for the device node, it is gone now.
168 	 */
169 	cam_periph_release_locked(periph);
170 
171 	/*
172 	 * We reference the lock directly here, instead of using
173 	 * cam_periph_unlock().  The reason is that the final call to
174 	 * cam_periph_release_locked() above could result in the periph
175 	 * getting freed.  If that is the case, dereferencing the periph
176 	 * with a cam_periph_unlock() call would cause a page fault.
177 	 */
178 	mtx_unlock(mtx);
179 }
180 
181 static void
182 passoninvalidate(struct cam_periph *periph)
183 {
184 	struct pass_softc *softc;
185 
186 	softc = (struct pass_softc *)periph->softc;
187 
188 	/*
189 	 * De-register any async callbacks.
190 	 */
191 	xpt_register_async(0, passasync, periph, periph->path);
192 
193 	softc->flags |= PASS_FLAG_INVALID;
194 
195 	/*
196 	 * Tell devfs this device has gone away, and ask for a callback
197 	 * when it has cleaned up its state.
198 	 */
199 	destroy_dev_sched_cb(softc->dev, passdevgonecb, periph);
200 
201 	/*
202 	 * XXX Return all queued I/O with ENXIO.
203 	 * XXX Handle any transactions queued to the card
204 	 *     with XPT_ABORT_CCB.
205 	 */
206 }
207 
208 static void
209 passcleanup(struct cam_periph *periph)
210 {
211 	struct pass_softc *softc;
212 
213 	softc = (struct pass_softc *)periph->softc;
214 
215 	devstat_remove_entry(softc->device_stats);
216 
217 	cam_periph_unlock(periph);
218 	taskqueue_drain(taskqueue_thread, &softc->add_physpath_task);
219 
220 	cam_periph_lock(periph);
221 
222 	free(softc, M_DEVBUF);
223 }
224 
225 static void
226 pass_add_physpath(void *context, int pending)
227 {
228 	struct cam_periph *periph;
229 	struct pass_softc *softc;
230 	char *physpath;
231 
232 	/*
233 	 * If we have one, create a devfs alias for our
234 	 * physical path.
235 	 */
236 	periph = context;
237 	softc = periph->softc;
238 	physpath = malloc(MAXPATHLEN, M_DEVBUF, M_WAITOK);
239 	cam_periph_lock(periph);
240 	if (periph->flags & CAM_PERIPH_INVALID) {
241 		cam_periph_unlock(periph);
242 		goto out;
243 	}
244 	if (xpt_getattr(physpath, MAXPATHLEN,
245 			"GEOM::physpath", periph->path) == 0
246 	 && strlen(physpath) != 0) {
247 
248 		cam_periph_unlock(periph);
249 		make_dev_physpath_alias(MAKEDEV_WAITOK, &softc->alias_dev,
250 					softc->dev, softc->alias_dev, physpath);
251 		cam_periph_lock(periph);
252 	}
253 
254 	/*
255 	 * Now that we've made our alias, we no longer have to have a
256 	 * reference to the device.
257 	 */
258 	if ((softc->flags & PASS_FLAG_INITIAL_PHYSPATH) == 0) {
259 		softc->flags |= PASS_FLAG_INITIAL_PHYSPATH;
260 		cam_periph_unlock(periph);
261 		dev_rel(softc->dev);
262 	}
263 	else
264 		cam_periph_unlock(periph);
265 
266 out:
267 	free(physpath, M_DEVBUF);
268 }
269 
270 static void
271 passasync(void *callback_arg, u_int32_t code,
272 	  struct cam_path *path, void *arg)
273 {
274 	struct cam_periph *periph;
275 
276 	periph = (struct cam_periph *)callback_arg;
277 
278 	switch (code) {
279 	case AC_FOUND_DEVICE:
280 	{
281 		struct ccb_getdev *cgd;
282 		cam_status status;
283 
284 		cgd = (struct ccb_getdev *)arg;
285 		if (cgd == NULL)
286 			break;
287 
288 		/*
289 		 * Allocate a peripheral instance for
290 		 * this device and start the probe
291 		 * process.
292 		 */
293 		status = cam_periph_alloc(passregister, passoninvalidate,
294 					  passcleanup, NULL, "pass",
295 					  CAM_PERIPH_BIO, path,
296 					  passasync, AC_FOUND_DEVICE, cgd);
297 
298 		if (status != CAM_REQ_CMP
299 		 && status != CAM_REQ_INPROG) {
300 			const struct cam_status_entry *entry;
301 
302 			entry = cam_fetch_status_entry(status);
303 
304 			printf("passasync: Unable to attach new device "
305 			       "due to status %#x: %s\n", status, entry ?
306 			       entry->status_text : "Unknown");
307 		}
308 
309 		break;
310 	}
311 	case AC_ADVINFO_CHANGED:
312 	{
313 		uintptr_t buftype;
314 
315 		buftype = (uintptr_t)arg;
316 		if (buftype == CDAI_TYPE_PHYS_PATH) {
317 			struct pass_softc *softc;
318 
319 			softc = (struct pass_softc *)periph->softc;
320 			taskqueue_enqueue(taskqueue_thread,
321 					  &softc->add_physpath_task);
322 		}
323 		break;
324 	}
325 	default:
326 		cam_periph_async(periph, code, path, arg);
327 		break;
328 	}
329 }
330 
331 static cam_status
332 passregister(struct cam_periph *periph, void *arg)
333 {
334 	struct pass_softc *softc;
335 	struct ccb_getdev *cgd;
336 	struct ccb_pathinq cpi;
337 	int    no_tags;
338 
339 	cgd = (struct ccb_getdev *)arg;
340 	if (cgd == NULL) {
341 		printf("%s: no getdev CCB, can't register device\n", __func__);
342 		return(CAM_REQ_CMP_ERR);
343 	}
344 
345 	softc = (struct pass_softc *)malloc(sizeof(*softc),
346 					    M_DEVBUF, M_NOWAIT);
347 
348 	if (softc == NULL) {
349 		printf("%s: Unable to probe new device. "
350 		       "Unable to allocate softc\n", __func__);
351 		return(CAM_REQ_CMP_ERR);
352 	}
353 
354 	bzero(softc, sizeof(*softc));
355 	softc->state = PASS_STATE_NORMAL;
356 	if (cgd->protocol == PROTO_SCSI || cgd->protocol == PROTO_ATAPI)
357 		softc->pd_type = SID_TYPE(&cgd->inq_data);
358 	else if (cgd->protocol == PROTO_SATAPM)
359 		softc->pd_type = T_ENCLOSURE;
360 	else
361 		softc->pd_type = T_DIRECT;
362 
363 	periph->softc = softc;
364 
365 	bzero(&cpi, sizeof(cpi));
366 	xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
367 	cpi.ccb_h.func_code = XPT_PATH_INQ;
368 	xpt_action((union ccb *)&cpi);
369 
370 	if (cpi.maxio == 0)
371 		softc->maxio = DFLTPHYS;	/* traditional default */
372 	else if (cpi.maxio > MAXPHYS)
373 		softc->maxio = MAXPHYS;		/* for safety */
374 	else
375 		softc->maxio = cpi.maxio;	/* real value */
376 
377 	/*
378 	 * We pass in 0 for a blocksize, since we don't
379 	 * know what the blocksize of this device is, if
380 	 * it even has a blocksize.
381 	 */
382 	cam_periph_unlock(periph);
383 	no_tags = (cgd->inq_data.flags & SID_CmdQue) == 0;
384 	softc->device_stats = devstat_new_entry("pass",
385 			  periph->unit_number, 0,
386 			  DEVSTAT_NO_BLOCKSIZE
387 			  | (no_tags ? DEVSTAT_NO_ORDERED_TAGS : 0),
388 			  softc->pd_type |
389 			  XPORT_DEVSTAT_TYPE(cpi.transport) |
390 			  DEVSTAT_TYPE_PASS,
391 			  DEVSTAT_PRIORITY_PASS);
392 
393 	/*
394 	 * Acquire a reference to the periph before we create the devfs
395 	 * instance for it.  We'll release this reference once the devfs
396 	 * instance has been freed.
397 	 */
398 	if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
399 		xpt_print(periph->path, "%s: lost periph during "
400 			  "registration!\n", __func__);
401 		cam_periph_lock(periph);
402 		return (CAM_REQ_CMP_ERR);
403 	}
404 
405 	/* Register the device */
406 	softc->dev = make_dev(&pass_cdevsw, periph->unit_number,
407 			      UID_ROOT, GID_OPERATOR, 0600, "%s%d",
408 			      periph->periph_name, periph->unit_number);
409 
410 	/*
411 	 * Now that we have made the devfs instance, hold a reference to it
412 	 * until the task queue has run to setup the physical path alias.
413 	 * That way devfs won't get rid of the device before we add our
414 	 * alias.
415 	 */
416 	dev_ref(softc->dev);
417 
418 	cam_periph_lock(periph);
419 	softc->dev->si_drv1 = periph;
420 
421 	TASK_INIT(&softc->add_physpath_task, /*priority*/0,
422 		  pass_add_physpath, periph);
423 
424 	/*
425 	 * See if physical path information is already available.
426 	 */
427 	taskqueue_enqueue(taskqueue_thread, &softc->add_physpath_task);
428 
429 	/*
430 	 * Add an async callback so that we get notified if
431 	 * this device goes away or its physical path
432 	 * (stored in the advanced info data of the EDT) has
433 	 * changed.
434 	 */
435 	xpt_register_async(AC_LOST_DEVICE | AC_ADVINFO_CHANGED,
436 			   passasync, periph, periph->path);
437 
438 	if (bootverbose)
439 		xpt_announce_periph(periph, NULL);
440 
441 	return(CAM_REQ_CMP);
442 }
443 
444 static int
445 passopen(struct cdev *dev, int flags, int fmt, struct thread *td)
446 {
447 	struct cam_periph *periph;
448 	struct pass_softc *softc;
449 	int error;
450 
451 	periph = (struct cam_periph *)dev->si_drv1;
452 	if (cam_periph_acquire(periph) != CAM_REQ_CMP)
453 		return (ENXIO);
454 
455 	cam_periph_lock(periph);
456 
457 	softc = (struct pass_softc *)periph->softc;
458 
459 	if (softc->flags & PASS_FLAG_INVALID) {
460 		cam_periph_release_locked(periph);
461 		cam_periph_unlock(periph);
462 		return(ENXIO);
463 	}
464 
465 	/*
466 	 * Don't allow access when we're running at a high securelevel.
467 	 */
468 	error = securelevel_gt(td->td_ucred, 1);
469 	if (error) {
470 		cam_periph_release_locked(periph);
471 		cam_periph_unlock(periph);
472 		return(error);
473 	}
474 
475 	/*
476 	 * Only allow read-write access.
477 	 */
478 	if (((flags & FWRITE) == 0) || ((flags & FREAD) == 0)) {
479 		cam_periph_release_locked(periph);
480 		cam_periph_unlock(periph);
481 		return(EPERM);
482 	}
483 
484 	/*
485 	 * We don't allow nonblocking access.
486 	 */
487 	if ((flags & O_NONBLOCK) != 0) {
488 		xpt_print(periph->path, "can't do nonblocking access\n");
489 		cam_periph_release_locked(periph);
490 		cam_periph_unlock(periph);
491 		return(EINVAL);
492 	}
493 
494 	softc->open_count++;
495 
496 	cam_periph_unlock(periph);
497 
498 	return (error);
499 }
500 
501 static int
502 passclose(struct cdev *dev, int flag, int fmt, struct thread *td)
503 {
504 	struct 	cam_periph *periph;
505 	struct  pass_softc *softc;
506 	struct mtx *mtx;
507 
508 	periph = (struct cam_periph *)dev->si_drv1;
509 	if (periph == NULL)
510 		return (ENXIO);
511 	mtx = cam_periph_mtx(periph);
512 	mtx_lock(mtx);
513 
514 	softc = periph->softc;
515 	softc->open_count--;
516 
517 	cam_periph_release_locked(periph);
518 
519 	/*
520 	 * We reference the lock directly here, instead of using
521 	 * cam_periph_unlock().  The reason is that the call to
522 	 * cam_periph_release_locked() above could result in the periph
523 	 * getting freed.  If that is the case, dereferencing the periph
524 	 * with a cam_periph_unlock() call would cause a page fault.
525 	 *
526 	 * cam_periph_release() avoids this problem using the same method,
527 	 * but we're manually acquiring and dropping the lock here to
528 	 * protect the open count and avoid another lock acquisition and
529 	 * release.
530 	 */
531 	mtx_unlock(mtx);
532 
533 	return (0);
534 }
535 
536 static int
537 passioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
538 {
539 	int error;
540 
541 	if ((error = passdoioctl(dev, cmd, addr, flag, td)) == ENOTTY) {
542 		error = cam_compat_ioctl(dev, cmd, addr, flag, td, passdoioctl);
543 	}
544 	return (error);
545 }
546 
547 static int
548 passdoioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
549 {
550 	struct	cam_periph *periph;
551 	int	error;
552 	uint32_t priority;
553 
554 	periph = (struct cam_periph *)dev->si_drv1;
555 	if (periph == NULL)
556 		return(ENXIO);
557 
558 	cam_periph_lock(periph);
559 
560 	error = 0;
561 
562 	switch (cmd) {
563 
564 	case CAMIOCOMMAND:
565 	{
566 		union ccb *inccb;
567 		union ccb *ccb;
568 		int ccb_malloced;
569 
570 		inccb = (union ccb *)addr;
571 
572 		/*
573 		 * Some CCB types, like scan bus and scan lun can only go
574 		 * through the transport layer device.
575 		 */
576 		if (inccb->ccb_h.func_code & XPT_FC_XPT_ONLY) {
577 			xpt_print(periph->path, "CCB function code %#x is "
578 			    "restricted to the XPT device\n",
579 			    inccb->ccb_h.func_code);
580 			error = ENODEV;
581 			break;
582 		}
583 
584 		/* Compatibility for RL/priority-unaware code. */
585 		priority = inccb->ccb_h.pinfo.priority;
586 		if (priority <= CAM_PRIORITY_OOB)
587 		    priority += CAM_PRIORITY_OOB + 1;
588 
589 		/*
590 		 * Non-immediate CCBs need a CCB from the per-device pool
591 		 * of CCBs, which is scheduled by the transport layer.
592 		 * Immediate CCBs and user-supplied CCBs should just be
593 		 * malloced.
594 		 */
595 		if ((inccb->ccb_h.func_code & XPT_FC_QUEUED)
596 		 && ((inccb->ccb_h.func_code & XPT_FC_USER_CCB) == 0)) {
597 			ccb = cam_periph_getccb(periph, priority);
598 			ccb_malloced = 0;
599 		} else {
600 			ccb = xpt_alloc_ccb_nowait();
601 
602 			if (ccb != NULL)
603 				xpt_setup_ccb(&ccb->ccb_h, periph->path,
604 					      priority);
605 			ccb_malloced = 1;
606 		}
607 
608 		if (ccb == NULL) {
609 			xpt_print(periph->path, "unable to allocate CCB\n");
610 			error = ENOMEM;
611 			break;
612 		}
613 
614 		error = passsendccb(periph, ccb, inccb);
615 
616 		if (ccb_malloced)
617 			xpt_free_ccb(ccb);
618 		else
619 			xpt_release_ccb(ccb);
620 
621 		break;
622 	}
623 	default:
624 		error = cam_periph_ioctl(periph, cmd, addr, passerror);
625 		break;
626 	}
627 
628 	cam_periph_unlock(periph);
629 	return(error);
630 }
631 
632 /*
633  * Generally, "ccb" should be the CCB supplied by the kernel.  "inccb"
634  * should be the CCB that is copied in from the user.
635  */
636 static int
637 passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb)
638 {
639 	struct pass_softc *softc;
640 	struct cam_periph_map_info mapinfo;
641 	xpt_opcode fc;
642 	int error;
643 
644 	softc = (struct pass_softc *)periph->softc;
645 
646 	/*
647 	 * There are some fields in the CCB header that need to be
648 	 * preserved, the rest we get from the user.
649 	 */
650 	xpt_merge_ccb(ccb, inccb);
651 
652 	/*
653 	 * Let cam_periph_mapmem do a sanity check on the data pointer format.
654 	 * Even if no data transfer is needed, it's a cheap check and it
655 	 * simplifies the code.
656 	 */
657 	fc = ccb->ccb_h.func_code;
658 	if ((fc == XPT_SCSI_IO) || (fc == XPT_ATA_IO) || (fc == XPT_SMP_IO)
659 	 || (fc == XPT_DEV_MATCH) || (fc == XPT_DEV_ADVINFO)) {
660 		bzero(&mapinfo, sizeof(mapinfo));
661 
662 		/*
663 		 * cam_periph_mapmem calls into proc and vm functions that can
664 		 * sleep as well as trigger I/O, so we can't hold the lock.
665 		 * Dropping it here is reasonably safe.
666 		 */
667 		cam_periph_unlock(periph);
668 		error = cam_periph_mapmem(ccb, &mapinfo, softc->maxio);
669 		cam_periph_lock(periph);
670 
671 		/*
672 		 * cam_periph_mapmem returned an error, we can't continue.
673 		 * Return the error to the user.
674 		 */
675 		if (error)
676 			return(error);
677 	} else
678 		/* Ensure that the unmap call later on is a no-op. */
679 		mapinfo.num_bufs_used = 0;
680 
681 	/*
682 	 * If the user wants us to perform any error recovery, then honor
683 	 * that request.  Otherwise, it's up to the user to perform any
684 	 * error recovery.
685 	 */
686 	cam_periph_runccb(ccb, passerror, /* cam_flags */ CAM_RETRY_SELTO,
687 	    /* sense_flags */ ((ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ?
688 	     SF_RETRY_UA : SF_NO_RECOVERY) | SF_NO_PRINT,
689 	    softc->device_stats);
690 
691 	cam_periph_unmapmem(ccb, &mapinfo);
692 
693 	ccb->ccb_h.cbfcnp = NULL;
694 	ccb->ccb_h.periph_priv = inccb->ccb_h.periph_priv;
695 	bcopy(ccb, inccb, sizeof(union ccb));
696 
697 	return(0);
698 }
699 
700 static int
701 passerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
702 {
703 	struct cam_periph *periph;
704 	struct pass_softc *softc;
705 
706 	periph = xpt_path_periph(ccb->ccb_h.path);
707 	softc = (struct pass_softc *)periph->softc;
708 
709 	return(cam_periph_error(ccb, cam_flags, sense_flags,
710 				 &softc->saved_ccb));
711 }
712