scsi_pass.c revision 241485
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 241485 2012-10-12 17:18:24Z 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
525	periph = (struct cam_periph *)dev->si_drv1;
526	if (periph == NULL)
527		return(ENXIO);
528
529	cam_periph_lock(periph);
530	softc = (struct pass_softc *)periph->softc;
531
532	error = 0;
533
534	switch (cmd) {
535
536	case CAMIOCOMMAND:
537	{
538		union ccb *inccb;
539		union ccb *ccb;
540		int ccb_malloced;
541
542		inccb = (union ccb *)addr;
543
544		/*
545		 * Some CCB types, like scan bus and scan lun can only go
546		 * through the transport layer device.
547		 */
548		if (inccb->ccb_h.func_code & XPT_FC_XPT_ONLY) {
549			xpt_print(periph->path, "CCB function code %#x is "
550			    "restricted to the XPT device\n",
551			    inccb->ccb_h.func_code);
552			error = ENODEV;
553			break;
554		}
555
556		/*
557		 * Non-immediate CCBs need a CCB from the per-device pool
558		 * of CCBs, which is scheduled by the transport layer.
559		 * Immediate CCBs and user-supplied CCBs should just be
560		 * malloced.
561		 */
562		if ((inccb->ccb_h.func_code & XPT_FC_QUEUED)
563		 && ((inccb->ccb_h.func_code & XPT_FC_USER_CCB) == 0)) {
564			ccb = cam_periph_getccb(periph,
565						inccb->ccb_h.pinfo.priority);
566			ccb_malloced = 0;
567		} else {
568			ccb = xpt_alloc_ccb_nowait();
569
570			if (ccb != NULL)
571				xpt_setup_ccb(&ccb->ccb_h, periph->path,
572					      inccb->ccb_h.pinfo.priority);
573			ccb_malloced = 1;
574		}
575
576		if (ccb == NULL) {
577			xpt_print(periph->path, "unable to allocate CCB\n");
578			error = ENOMEM;
579			break;
580		}
581
582		error = passsendccb(periph, ccb, inccb);
583
584		if (ccb_malloced)
585			xpt_free_ccb(ccb);
586		else
587			xpt_release_ccb(ccb);
588
589		break;
590	}
591	default:
592		error = cam_periph_ioctl(periph, cmd, addr, passerror);
593		break;
594	}
595
596	cam_periph_unlock(periph);
597	return(error);
598}
599
600/*
601 * Generally, "ccb" should be the CCB supplied by the kernel.  "inccb"
602 * should be the CCB that is copied in from the user.
603 */
604static int
605passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb)
606{
607	struct pass_softc *softc;
608	struct cam_periph_map_info mapinfo;
609	int error, need_unmap;
610
611	softc = (struct pass_softc *)periph->softc;
612
613	need_unmap = 0;
614
615	/*
616	 * There are some fields in the CCB header that need to be
617	 * preserved, the rest we get from the user.
618	 */
619	xpt_merge_ccb(ccb, inccb);
620
621	/*
622	 * There's no way for the user to have a completion
623	 * function, so we put our own completion function in here.
624	 */
625	ccb->ccb_h.cbfcnp = passdone;
626
627	/*
628	 * We only attempt to map the user memory into kernel space
629	 * if they haven't passed in a physical memory pointer,
630	 * and if there is actually an I/O operation to perform.
631	 * cam_periph_mapmem() supports SCSI, ATA, SMP, ADVINFO and device
632	 * match CCBs.  For the SCSI, ATA and ADVINFO CCBs, we only pass the
633	 * CCB in if there's actually data to map.  cam_periph_mapmem() will
634	 * do the right thing, even if there isn't data to map, but since CCBs
635	 * without data are a reasonably common occurance (e.g. test unit
636	 * ready), it will save a few cycles if we check for it here.
637	 */
638	if (((ccb->ccb_h.flags & CAM_DATA_PHYS) == 0)
639	 && (((ccb->ccb_h.func_code == XPT_SCSI_IO ||
640	       ccb->ccb_h.func_code == XPT_ATA_IO)
641	    && ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE))
642	  || (ccb->ccb_h.func_code == XPT_DEV_MATCH)
643	  || (ccb->ccb_h.func_code == XPT_SMP_IO)
644	  || ((ccb->ccb_h.func_code == XPT_DEV_ADVINFO)
645	   && (ccb->cdai.bufsiz > 0)))) {
646
647		bzero(&mapinfo, sizeof(mapinfo));
648
649		/*
650		 * cam_periph_mapmem calls into proc and vm functions that can
651		 * sleep as well as trigger I/O, so we can't hold the lock.
652		 * Dropping it here is reasonably safe.
653		 */
654		cam_periph_unlock(periph);
655		error = cam_periph_mapmem(ccb, &mapinfo);
656		cam_periph_lock(periph);
657
658		/*
659		 * cam_periph_mapmem returned an error, we can't continue.
660		 * Return the error to the user.
661		 */
662		if (error)
663			return(error);
664
665		/*
666		 * We successfully mapped the memory in, so we need to
667		 * unmap it when the transaction is done.
668		 */
669		need_unmap = 1;
670	}
671
672	/*
673	 * If the user wants us to perform any error recovery, then honor
674	 * that request.  Otherwise, it's up to the user to perform any
675	 * error recovery.
676	 */
677	cam_periph_runccb(ccb, passerror, /* cam_flags */ CAM_RETRY_SELTO,
678	    /* sense_flags */ ((ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ?
679	     SF_RETRY_UA : SF_NO_RECOVERY) | SF_NO_PRINT,
680	    softc->device_stats);
681
682	if (need_unmap != 0)
683		cam_periph_unmapmem(ccb, &mapinfo);
684
685	ccb->ccb_h.cbfcnp = NULL;
686	ccb->ccb_h.periph_priv = inccb->ccb_h.periph_priv;
687	bcopy(ccb, inccb, sizeof(union ccb));
688
689	return(0);
690}
691
692static int
693passerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
694{
695	struct cam_periph *periph;
696	struct pass_softc *softc;
697
698	periph = xpt_path_periph(ccb->ccb_h.path);
699	softc = (struct pass_softc *)periph->softc;
700
701	return(cam_periph_error(ccb, cam_flags, sense_flags,
702				 &softc->saved_ccb));
703}
704