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