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