scsi_pass.c revision 263954
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 263954 2014-03-30 23:43:36Z imp $");
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
56typedef 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
63typedef enum {
64	PASS_STATE_NORMAL
65} pass_state;
66
67typedef enum {
68	PASS_CCB_BUFFER_IO
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	int		 open_count;
80	struct devstat	*device_stats;
81	struct cdev	*dev;
82	struct cdev	*alias_dev;
83	struct task	 add_physpath_task;
84};
85
86
87static	d_open_t	passopen;
88static	d_close_t	passclose;
89static	d_ioctl_t	passioctl;
90static	d_ioctl_t	passdoioctl;
91
92static	periph_init_t	passinit;
93static	periph_ctor_t	passregister;
94static	periph_oninv_t	passoninvalidate;
95static	periph_dtor_t	passcleanup;
96static void		pass_add_physpath(void *context, int pending);
97static	void		passasync(void *callback_arg, u_int32_t code,
98				  struct cam_path *path, void *arg);
99static	int		passerror(union ccb *ccb, u_int32_t cam_flags,
100				  u_int32_t sense_flags);
101static 	int		passsendccb(struct cam_periph *periph, union ccb *ccb,
102				    union ccb *inccb);
103
104static struct periph_driver passdriver =
105{
106	passinit, "pass",
107	TAILQ_HEAD_INITIALIZER(passdriver.units), /* generation */ 0
108};
109
110PERIPHDRIVER_DECLARE(pass, passdriver);
111
112static struct cdevsw pass_cdevsw = {
113	.d_version =	D_VERSION,
114	.d_flags =	D_TRACKCLOSE,
115	.d_open =	passopen,
116	.d_close =	passclose,
117	.d_ioctl =	passioctl,
118	.d_name =	"pass",
119};
120
121static void
122passinit(void)
123{
124	cam_status status;
125
126	/*
127	 * Install a global async callback.  This callback will
128	 * receive async callbacks like "new device found".
129	 */
130	status = xpt_register_async(AC_FOUND_DEVICE, passasync, NULL, NULL);
131
132	if (status != CAM_REQ_CMP) {
133		printf("pass: Failed to attach master async callback "
134		       "due to status 0x%x!\n", status);
135	}
136
137}
138
139static void
140passdevgonecb(void *arg)
141{
142	struct cam_periph *periph;
143	struct mtx *mtx;
144	struct pass_softc *softc;
145	int i;
146
147	periph = (struct cam_periph *)arg;
148	mtx = cam_periph_mtx(periph);
149	mtx_lock(mtx);
150
151	softc = (struct pass_softc *)periph->softc;
152	KASSERT(softc->open_count >= 0, ("Negative open count %d",
153		softc->open_count));
154
155	/*
156	 * When we get this callback, we will get no more close calls from
157	 * devfs.  So if we have any dangling opens, we need to release the
158	 * reference held for that particular context.
159	 */
160	for (i = 0; i < softc->open_count; i++)
161		cam_periph_release_locked(periph);
162
163	softc->open_count = 0;
164
165	/*
166	 * Release the reference held for the device node, it is gone now.
167	 */
168	cam_periph_release_locked(periph);
169
170	/*
171	 * We reference the lock directly here, instead of using
172	 * cam_periph_unlock().  The reason is that the final call to
173	 * cam_periph_release_locked() above could result in the periph
174	 * getting freed.  If that is the case, dereferencing the periph
175	 * with a cam_periph_unlock() call would cause a page fault.
176	 */
177	mtx_unlock(mtx);
178}
179
180static void
181passoninvalidate(struct cam_periph *periph)
182{
183	struct pass_softc *softc;
184
185	softc = (struct pass_softc *)periph->softc;
186
187	/*
188	 * De-register any async callbacks.
189	 */
190	xpt_register_async(0, passasync, periph, periph->path);
191
192	softc->flags |= PASS_FLAG_INVALID;
193
194	/*
195	 * Tell devfs this device has gone away, and ask for a callback
196	 * when it has cleaned up its state.
197	 */
198	destroy_dev_sched_cb(softc->dev, passdevgonecb, periph);
199
200	/*
201	 * XXX Return all queued I/O with ENXIO.
202	 * XXX Handle any transactions queued to the card
203	 *     with XPT_ABORT_CCB.
204	 */
205}
206
207static void
208passcleanup(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	int	error;
544	uint32_t priority;
545
546	periph = (struct cam_periph *)dev->si_drv1;
547	if (periph == NULL)
548		return(ENXIO);
549
550	cam_periph_lock(periph);
551
552	error = 0;
553
554	switch (cmd) {
555
556	case CAMIOCOMMAND:
557	{
558		union ccb *inccb;
559		union ccb *ccb;
560		int ccb_malloced;
561
562		inccb = (union ccb *)addr;
563
564		/*
565		 * Some CCB types, like scan bus and scan lun can only go
566		 * through the transport layer device.
567		 */
568		if (inccb->ccb_h.func_code & XPT_FC_XPT_ONLY) {
569			xpt_print(periph->path, "CCB function code %#x is "
570			    "restricted to the XPT device\n",
571			    inccb->ccb_h.func_code);
572			error = ENODEV;
573			break;
574		}
575
576		/* Compatibility for RL/priority-unaware code. */
577		priority = inccb->ccb_h.pinfo.priority;
578		if (priority <= CAM_PRIORITY_OOB)
579		    priority += CAM_PRIORITY_OOB + 1;
580
581		/*
582		 * Non-immediate CCBs need a CCB from the per-device pool
583		 * of CCBs, which is scheduled by the transport layer.
584		 * Immediate CCBs and user-supplied CCBs should just be
585		 * malloced.
586		 */
587		if ((inccb->ccb_h.func_code & XPT_FC_QUEUED)
588		 && ((inccb->ccb_h.func_code & XPT_FC_USER_CCB) == 0)) {
589			ccb = cam_periph_getccb(periph, priority);
590			ccb_malloced = 0;
591		} else {
592			ccb = xpt_alloc_ccb_nowait();
593
594			if (ccb != NULL)
595				xpt_setup_ccb(&ccb->ccb_h, periph->path,
596					      priority);
597			ccb_malloced = 1;
598		}
599
600		if (ccb == NULL) {
601			xpt_print(periph->path, "unable to allocate CCB\n");
602			error = ENOMEM;
603			break;
604		}
605
606		error = passsendccb(periph, ccb, inccb);
607
608		if (ccb_malloced)
609			xpt_free_ccb(ccb);
610		else
611			xpt_release_ccb(ccb);
612
613		break;
614	}
615	default:
616		error = cam_periph_ioctl(periph, cmd, addr, passerror);
617		break;
618	}
619
620	cam_periph_unlock(periph);
621	return(error);
622}
623
624/*
625 * Generally, "ccb" should be the CCB supplied by the kernel.  "inccb"
626 * should be the CCB that is copied in from the user.
627 */
628static int
629passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb)
630{
631	struct pass_softc *softc;
632	struct cam_periph_map_info mapinfo;
633	xpt_opcode fc;
634	int error;
635
636	softc = (struct pass_softc *)periph->softc;
637
638	/*
639	 * There are some fields in the CCB header that need to be
640	 * preserved, the rest we get from the user.
641	 */
642	xpt_merge_ccb(ccb, inccb);
643
644	/*
645	 * Let cam_periph_mapmem do a sanity check on the data pointer format.
646	 * Even if no data transfer is needed, it's a cheap check and it
647	 * simplifies the code.
648	 */
649	fc = ccb->ccb_h.func_code;
650	if ((fc == XPT_SCSI_IO) || (fc == XPT_ATA_IO) || (fc == XPT_SMP_IO)
651	 || (fc == XPT_DEV_MATCH) || (fc == XPT_DEV_ADVINFO)) {
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	} else
670		/* Ensure that the unmap call later on is a no-op. */
671		mapinfo.num_bufs_used = 0;
672
673	/*
674	 * If the user wants us to perform any error recovery, then honor
675	 * that request.  Otherwise, it's up to the user to perform any
676	 * error recovery.
677	 */
678	cam_periph_runccb(ccb, passerror, /* cam_flags */ CAM_RETRY_SELTO,
679	    /* sense_flags */ ((ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ?
680	     SF_RETRY_UA : SF_NO_RECOVERY) | SF_NO_PRINT,
681	    softc->device_stats);
682
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