1 /*-
2  * Copyright (c) 2000 Matthew Jacob
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions, and the following disclaimer,
10  *    without modification, immediately at the beginning of the file.
11  * 2. The name of the author may not be used to endorse or promote products
12  *    derived from this software without specific prior written permission.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
18  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD: stable/9/sys/cam/scsi/scsi_enc.c 257050 2013-10-24 10:34:13Z mav $");
29 
30 #include <sys/param.h>
31 
32 #include <sys/conf.h>
33 #include <sys/errno.h>
34 #include <sys/fcntl.h>
35 #include <sys/kernel.h>
36 #include <sys/kthread.h>
37 #include <sys/lock.h>
38 #include <sys/malloc.h>
39 #include <sys/mutex.h>
40 #include <sys/queue.h>
41 #include <sys/sx.h>
42 #include <sys/systm.h>
43 #include <sys/sysctl.h>
44 #include <sys/types.h>
45 
46 #include <machine/stdarg.h>
47 
48 #include <cam/cam.h>
49 #include <cam/cam_ccb.h>
50 #include <cam/cam_debug.h>
51 #include <cam/cam_periph.h>
52 #include <cam/cam_xpt_periph.h>
53 
54 #include <cam/scsi/scsi_all.h>
55 #include <cam/scsi/scsi_message.h>
56 #include <cam/scsi/scsi_enc.h>
57 #include <cam/scsi/scsi_enc_internal.h>
58 
59 #include <opt_ses.h>
60 
61 MALLOC_DEFINE(M_SCSIENC, "SCSI ENC", "SCSI ENC buffers");
62 
63 /* Enclosure type independent driver */
64 
65 static	d_open_t	enc_open;
66 static	d_close_t	enc_close;
67 static	d_ioctl_t	enc_ioctl;
68 static	periph_init_t	enc_init;
69 static  periph_ctor_t	enc_ctor;
70 static	periph_oninv_t	enc_oninvalidate;
71 static  periph_dtor_t   enc_dtor;
72 static  periph_start_t  enc_start;
73 
74 static void enc_async(void *, uint32_t, struct cam_path *, void *);
75 static enctyp enc_type(struct ccb_getdev *);
76 
77 SYSCTL_NODE(_kern_cam, OID_AUTO, enc, CTLFLAG_RD, 0,
78             "CAM Enclosure Services driver");
79 
80 static struct periph_driver encdriver = {
81 	enc_init, "ses",
82 	TAILQ_HEAD_INITIALIZER(encdriver.units), /* generation */ 0
83 };
84 
85 PERIPHDRIVER_DECLARE(enc, encdriver);
86 
87 static struct cdevsw enc_cdevsw = {
88 	.d_version =	D_VERSION,
89 	.d_open =	enc_open,
90 	.d_close =	enc_close,
91 	.d_ioctl =	enc_ioctl,
92 	.d_name =	"ses",
93 	.d_flags =	D_TRACKCLOSE,
94 };
95 
96 static void
enc_init(void)97 enc_init(void)
98 {
99 	cam_status status;
100 
101 	/*
102 	 * Install a global async callback.  This callback will
103 	 * receive async callbacks like "new device found".
104 	 */
105 	status = xpt_register_async(AC_FOUND_DEVICE, enc_async, NULL, NULL);
106 
107 	if (status != CAM_REQ_CMP) {
108 		printf("enc: Failed to attach master async callback "
109 		       "due to status 0x%x!\n", status);
110 	}
111 }
112 
113 static void
enc_devgonecb(void * arg)114 enc_devgonecb(void *arg)
115 {
116 	struct cam_sim    *sim;
117 	struct cam_periph *periph;
118 	struct enc_softc  *enc;
119 	int i;
120 
121 	periph = (struct cam_periph *)arg;
122 	sim = periph->sim;
123 	enc = (struct enc_softc *)periph->softc;
124 
125 	mtx_lock(sim->mtx);
126 
127 	/*
128 	 * When we get this callback, we will get no more close calls from
129 	 * devfs.  So if we have any dangling opens, we need to release the
130 	 * reference held for that particular context.
131 	 */
132 	for (i = 0; i < enc->open_count; i++)
133 		cam_periph_release_locked(periph);
134 
135 	enc->open_count = 0;
136 
137 	/*
138 	 * Release the reference held for the device node, it is gone now.
139 	 */
140 	cam_periph_release_locked(periph);
141 
142 	/*
143 	 * We reference the SIM lock directly here, instead of using
144 	 * cam_periph_unlock().  The reason is that the final call to
145 	 * cam_periph_release_locked() above could result in the periph
146 	 * getting freed.  If that is the case, dereferencing the periph
147 	 * with a cam_periph_unlock() call would cause a page fault.
148 	 */
149 	mtx_unlock(sim->mtx);
150 }
151 
152 static void
enc_oninvalidate(struct cam_periph * periph)153 enc_oninvalidate(struct cam_periph *periph)
154 {
155 	struct enc_softc *enc;
156 
157 	enc = periph->softc;
158 
159 	enc->enc_flags |= ENC_FLAG_INVALID;
160 
161 	/* If the sub-driver has an invalidate routine, call it */
162 	if (enc->enc_vec.softc_invalidate != NULL)
163 		enc->enc_vec.softc_invalidate(enc);
164 
165 	/*
166 	 * Unregister any async callbacks.
167 	 */
168 	xpt_register_async(0, enc_async, periph, periph->path);
169 
170 	/*
171 	 * Shutdown our daemon.
172 	 */
173 	enc->enc_flags |= ENC_FLAG_SHUTDOWN;
174 	if (enc->enc_daemon != NULL) {
175 		/* Signal the ses daemon to terminate. */
176 		wakeup(enc->enc_daemon);
177 	}
178 	callout_drain(&enc->status_updater);
179 
180 	destroy_dev_sched_cb(enc->enc_dev, enc_devgonecb, periph);
181 }
182 
183 static void
enc_dtor(struct cam_periph * periph)184 enc_dtor(struct cam_periph *periph)
185 {
186 	struct enc_softc *enc;
187 
188 	enc = periph->softc;
189 
190 	/* If the sub-driver has a cleanup routine, call it */
191 	if (enc->enc_vec.softc_cleanup != NULL)
192 		enc->enc_vec.softc_cleanup(enc);
193 
194 	if (enc->enc_boot_hold_ch.ich_func != NULL) {
195 		config_intrhook_disestablish(&enc->enc_boot_hold_ch);
196 		enc->enc_boot_hold_ch.ich_func = NULL;
197 	}
198 
199 	ENC_FREE(enc);
200 }
201 
202 static void
enc_async(void * callback_arg,uint32_t code,struct cam_path * path,void * arg)203 enc_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
204 {
205 	struct cam_periph *periph;
206 
207 	periph = (struct cam_periph *)callback_arg;
208 
209 	switch(code) {
210 	case AC_FOUND_DEVICE:
211 	{
212 		struct ccb_getdev *cgd;
213 		cam_status status;
214 		path_id_t path_id;
215 
216 		cgd = (struct ccb_getdev *)arg;
217 		if (arg == NULL) {
218 			break;
219 		}
220 
221 		if (enc_type(cgd) == ENC_NONE) {
222 			/*
223 			 * Schedule announcement of the ENC bindings for
224 			 * this device if it is managed by a SEP.
225 			 */
226 			path_id = xpt_path_path_id(path);
227 			xpt_lock_buses();
228 			TAILQ_FOREACH(periph, &encdriver.units, unit_links) {
229 				struct enc_softc *softc;
230 
231 				softc = (struct enc_softc *)periph->softc;
232 				if (xpt_path_path_id(periph->path) != path_id
233 				 || softc == NULL
234 				 || (softc->enc_flags & ENC_FLAG_INITIALIZED)
235 				  == 0
236 				 || softc->enc_vec.device_found == NULL)
237 					continue;
238 
239 				softc->enc_vec.device_found(softc);
240 			}
241 			xpt_unlock_buses();
242 			return;
243 		}
244 
245 		status = cam_periph_alloc(enc_ctor, enc_oninvalidate,
246 		    enc_dtor, enc_start, "ses", CAM_PERIPH_BIO,
247 		    cgd->ccb_h.path, enc_async, AC_FOUND_DEVICE, cgd);
248 
249 		if (status != CAM_REQ_CMP && status != CAM_REQ_INPROG) {
250 			printf("enc_async: Unable to probe new device due to "
251 			    "status 0x%x\n", status);
252 		}
253 		break;
254 	}
255 	default:
256 		cam_periph_async(periph, code, path, arg);
257 		break;
258 	}
259 }
260 
261 static int
enc_open(struct cdev * dev,int flags,int fmt,struct thread * td)262 enc_open(struct cdev *dev, int flags, int fmt, struct thread *td)
263 {
264 	struct cam_periph *periph;
265 	struct enc_softc *softc;
266 	int error = 0;
267 
268 	periph = (struct cam_periph *)dev->si_drv1;
269 	if (periph == NULL) {
270 		return (ENXIO);
271 	}
272 
273 	if (cam_periph_acquire(periph) != CAM_REQ_CMP)
274 		return (ENXIO);
275 
276 	cam_periph_lock(periph);
277 
278 	softc = (struct enc_softc *)periph->softc;
279 
280 	if ((softc->enc_flags & ENC_FLAG_INITIALIZED) == 0) {
281 		error = ENXIO;
282 		goto out;
283 	}
284 	if (softc->enc_flags & ENC_FLAG_INVALID) {
285 		error = ENXIO;
286 		goto out;
287 	}
288 out:
289 	if (error != 0)
290 		cam_periph_release_locked(periph);
291 	else
292 		softc->open_count++;
293 
294 	cam_periph_unlock(periph);
295 
296 	return (error);
297 }
298 
299 static int
enc_close(struct cdev * dev,int flag,int fmt,struct thread * td)300 enc_close(struct cdev *dev, int flag, int fmt, struct thread *td)
301 {
302 	struct cam_sim    *sim;
303 	struct cam_periph *periph;
304 	struct enc_softc  *enc;
305 
306 	periph = (struct cam_periph *)dev->si_drv1;
307 	if (periph == NULL)
308 		return (ENXIO);
309 
310 	sim = periph->sim;
311 	enc = periph->softc;
312 
313 	mtx_lock(sim->mtx);
314 
315 	enc->open_count--;
316 
317 	cam_periph_release_locked(periph);
318 
319 	/*
320 	 * We reference the SIM lock directly here, instead of using
321 	 * cam_periph_unlock().  The reason is that the call to
322 	 * cam_periph_release_locked() above could result in the periph
323 	 * getting freed.  If that is the case, dereferencing the periph
324 	 * with a cam_periph_unlock() call would cause a page fault.
325 	 *
326 	 * cam_periph_release() avoids this problem using the same method,
327 	 * but we're manually acquiring and dropping the lock here to
328 	 * protect the open count and avoid another lock acquisition and
329 	 * release.
330 	 */
331 	mtx_unlock(sim->mtx);
332 
333 	return (0);
334 }
335 
336 static void
enc_start(struct cam_periph * p,union ccb * sccb)337 enc_start(struct cam_periph *p, union ccb *sccb)
338 {
339 	struct enc_softc *enc;
340 
341 	enc = p->softc;
342 	ENC_DLOG(enc, "%s enter imm=%d prio=%d\n",
343 	    __func__, p->immediate_priority, p->pinfo.priority);
344 	if (p->immediate_priority <= p->pinfo.priority) {
345 		SLIST_INSERT_HEAD(&p->ccb_list, &sccb->ccb_h, periph_links.sle);
346 		p->immediate_priority = CAM_PRIORITY_NONE;
347 		wakeup(&p->ccb_list);
348 	} else
349 		xpt_release_ccb(sccb);
350 	ENC_DLOG(enc, "%s exit\n", __func__);
351 }
352 
353 void
enc_done(struct cam_periph * periph,union ccb * dccb)354 enc_done(struct cam_periph *periph, union ccb *dccb)
355 {
356 	wakeup(&dccb->ccb_h.cbfcnp);
357 }
358 
359 int
enc_error(union ccb * ccb,uint32_t cflags,uint32_t sflags)360 enc_error(union ccb *ccb, uint32_t cflags, uint32_t sflags)
361 {
362 	struct enc_softc *softc;
363 	struct cam_periph *periph;
364 
365 	periph = xpt_path_periph(ccb->ccb_h.path);
366 	softc = (struct enc_softc *)periph->softc;
367 
368 	return (cam_periph_error(ccb, cflags, sflags, &softc->saved_ccb));
369 }
370 
371 static int
enc_ioctl(struct cdev * dev,u_long cmd,caddr_t arg_addr,int flag,struct thread * td)372 enc_ioctl(struct cdev *dev, u_long cmd, caddr_t arg_addr, int flag,
373 	 struct thread *td)
374 {
375 	struct cam_periph *periph;
376 	encioc_enc_status_t tmp;
377 	encioc_string_t sstr;
378 	encioc_elm_status_t elms;
379 	encioc_elm_desc_t elmd;
380 	encioc_elm_devnames_t elmdn;
381 	encioc_element_t *uelm;
382 	enc_softc_t *enc;
383 	enc_cache_t *cache;
384 	void *addr;
385 	int error, i;
386 
387 
388 	if (arg_addr)
389 		addr = *((caddr_t *) arg_addr);
390 	else
391 		addr = NULL;
392 
393 	periph = (struct cam_periph *)dev->si_drv1;
394 	if (periph == NULL)
395 		return (ENXIO);
396 
397 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering encioctl\n"));
398 
399 	cam_periph_lock(periph);
400 	enc = (struct enc_softc *)periph->softc;
401 	cache = &enc->enc_cache;
402 
403 	/*
404 	 * Now check to see whether we're initialized or not.
405 	 * This actually should never fail as we're not supposed
406 	 * to get past enc_open w/o successfully initializing
407 	 * things.
408 	 */
409 	if ((enc->enc_flags & ENC_FLAG_INITIALIZED) == 0) {
410 		cam_periph_unlock(periph);
411 		return (ENXIO);
412 	}
413 	cam_periph_unlock(periph);
414 
415 	error = 0;
416 
417 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
418 	    ("trying to do ioctl %#lx\n", cmd));
419 
420 	/*
421 	 * If this command can change the device's state,
422 	 * we must have the device open for writing.
423 	 *
424 	 * For commands that get information about the
425 	 * device- we don't need to lock the peripheral
426 	 * if we aren't running a command.  The periph
427 	 * also can't go away while a user process has
428 	 * it open.
429 	 */
430 	switch (cmd) {
431 	case ENCIOC_GETNELM:
432 	case ENCIOC_GETELMMAP:
433 	case ENCIOC_GETENCSTAT:
434 	case ENCIOC_GETELMSTAT:
435 	case ENCIOC_GETELMDESC:
436 	case ENCIOC_GETELMDEVNAMES:
437 		break;
438 	default:
439 		if ((flag & FWRITE) == 0) {
440 			return (EBADF);
441 		}
442 	}
443 
444 	/*
445 	 * XXX The values read here are only valid for the current
446 	 *     configuration generation.  We need these ioctls
447 	 *     to also pass in/out a generation number.
448 	 */
449 	sx_slock(&enc->enc_cache_lock);
450 	switch (cmd) {
451 	case ENCIOC_GETNELM:
452 		error = copyout(&cache->nelms, addr, sizeof (cache->nelms));
453 		break;
454 
455 	case ENCIOC_GETELMMAP:
456 		for (uelm = addr, i = 0; i != cache->nelms; i++) {
457 			encioc_element_t kelm;
458 			kelm.elm_idx = i;
459 			kelm.elm_subenc_id = cache->elm_map[i].subenclosure;
460 			kelm.elm_type = cache->elm_map[i].enctype;
461 			error = copyout(&kelm, &uelm[i], sizeof(kelm));
462 			if (error)
463 				break;
464 		}
465 		break;
466 
467 	case ENCIOC_GETENCSTAT:
468 		cam_periph_lock(periph);
469 		error = enc->enc_vec.get_enc_status(enc, 1);
470 		if (error) {
471 			cam_periph_unlock(periph);
472 			break;
473 		}
474 		tmp = cache->enc_status;
475 		cam_periph_unlock(periph);
476 		error = copyout(&tmp, addr, sizeof(tmp));
477 		cache->enc_status = tmp;
478 		break;
479 
480 	case ENCIOC_SETENCSTAT:
481 		error = copyin(addr, &tmp, sizeof(tmp));
482 		if (error)
483 			break;
484 		cam_periph_lock(periph);
485 		error = enc->enc_vec.set_enc_status(enc, tmp, 1);
486 		cam_periph_unlock(periph);
487 		break;
488 
489 	case ENCIOC_GETSTRING:
490 	case ENCIOC_SETSTRING:
491 		if (enc->enc_vec.handle_string == NULL) {
492 			error = EINVAL;
493 			break;
494 		}
495 		error = copyin(addr, &sstr, sizeof(sstr));
496 		if (error)
497 			break;
498 		cam_periph_lock(periph);
499 		error = enc->enc_vec.handle_string(enc, &sstr, cmd);
500 		cam_periph_unlock(periph);
501 		break;
502 
503 	case ENCIOC_GETELMSTAT:
504 		error = copyin(addr, &elms, sizeof(elms));
505 		if (error)
506 			break;
507 		if (elms.elm_idx >= cache->nelms) {
508 			error = EINVAL;
509 			break;
510 		}
511 		cam_periph_lock(periph);
512 		error = enc->enc_vec.get_elm_status(enc, &elms, 1);
513 		cam_periph_unlock(periph);
514 		if (error)
515 			break;
516 		error = copyout(&elms, addr, sizeof(elms));
517 		break;
518 
519 	case ENCIOC_GETELMDESC:
520 		error = copyin(addr, &elmd, sizeof(elmd));
521 		if (error)
522 			break;
523 		if (elmd.elm_idx >= cache->nelms) {
524 			error = EINVAL;
525 			break;
526 		}
527 		if (enc->enc_vec.get_elm_desc != NULL) {
528 			error = enc->enc_vec.get_elm_desc(enc, &elmd);
529 			if (error)
530 				break;
531 		} else
532 			elmd.elm_desc_len = 0;
533 		error = copyout(&elmd, addr, sizeof(elmd));
534 		break;
535 
536 	case ENCIOC_GETELMDEVNAMES:
537 		if (enc->enc_vec.get_elm_devnames == NULL) {
538 			error = EINVAL;
539 			break;
540 		}
541 		error = copyin(addr, &elmdn, sizeof(elmdn));
542 		if (error)
543 			break;
544 		if (elmdn.elm_idx >= cache->nelms) {
545 			error = EINVAL;
546 			break;
547 		}
548 		cam_periph_lock(periph);
549 		error = (*enc->enc_vec.get_elm_devnames)(enc, &elmdn);
550 		cam_periph_unlock(periph);
551 		if (error)
552 			break;
553 		error = copyout(&elmdn, addr, sizeof(elmdn));
554 		break;
555 
556 	case ENCIOC_SETELMSTAT:
557 		error = copyin(addr, &elms, sizeof(elms));
558 		if (error)
559 			break;
560 
561 		if (elms.elm_idx >= cache->nelms) {
562 			error = EINVAL;
563 			break;
564 		}
565 		cam_periph_lock(periph);
566 		error = enc->enc_vec.set_elm_status(enc, &elms, 1);
567 		cam_periph_unlock(periph);
568 
569 		break;
570 
571 	case ENCIOC_INIT:
572 
573 		cam_periph_lock(periph);
574 		error = enc->enc_vec.init_enc(enc);
575 		cam_periph_unlock(periph);
576 		break;
577 
578 	default:
579 		cam_periph_lock(periph);
580 		error = cam_periph_ioctl(periph, cmd, arg_addr, enc_error);
581 		cam_periph_unlock(periph);
582 		break;
583 	}
584 	sx_sunlock(&enc->enc_cache_lock);
585 	return (error);
586 }
587 
588 int
enc_runcmd(struct enc_softc * enc,char * cdb,int cdbl,char * dptr,int * dlenp)589 enc_runcmd(struct enc_softc *enc, char *cdb, int cdbl, char *dptr, int *dlenp)
590 {
591 	int error, dlen, tdlen;
592 	ccb_flags ddf;
593 	union ccb *ccb;
594 
595 	CAM_DEBUG(enc->periph->path, CAM_DEBUG_TRACE,
596 	    ("entering enc_runcmd\n"));
597 	if (dptr) {
598 		if ((dlen = *dlenp) < 0) {
599 			dlen = -dlen;
600 			ddf = CAM_DIR_OUT;
601 		} else {
602 			ddf = CAM_DIR_IN;
603 		}
604 	} else {
605 		dlen = 0;
606 		ddf = CAM_DIR_NONE;
607 	}
608 
609 	if (cdbl > IOCDBLEN) {
610 		cdbl = IOCDBLEN;
611 	}
612 
613 	ccb = cam_periph_getccb(enc->periph, CAM_PRIORITY_NORMAL);
614 	if (enc->enc_type == ENC_SEMB_SES || enc->enc_type == ENC_SEMB_SAFT) {
615 		tdlen = min(dlen, 1020);
616 		tdlen = (tdlen + 3) & ~3;
617 		cam_fill_ataio(&ccb->ataio, 0, enc_done, ddf, 0, dptr, tdlen,
618 		    30 * 1000);
619 		if (cdb[0] == RECEIVE_DIAGNOSTIC)
620 			ata_28bit_cmd(&ccb->ataio,
621 			    ATA_SEP_ATTN, cdb[2], 0x02, tdlen / 4);
622 		else if (cdb[0] == SEND_DIAGNOSTIC)
623 			ata_28bit_cmd(&ccb->ataio,
624 			    ATA_SEP_ATTN, dlen > 0 ? dptr[0] : 0,
625 			    0x82, tdlen / 4);
626 		else if (cdb[0] == READ_BUFFER)
627 			ata_28bit_cmd(&ccb->ataio,
628 			    ATA_SEP_ATTN, cdb[2], 0x00, tdlen / 4);
629 		else
630 			ata_28bit_cmd(&ccb->ataio,
631 			    ATA_SEP_ATTN, dlen > 0 ? dptr[0] : 0,
632 			    0x80, tdlen / 4);
633 	} else {
634 		tdlen = dlen;
635 		cam_fill_csio(&ccb->csio, 0, enc_done, ddf, MSG_SIMPLE_Q_TAG,
636 		    dptr, dlen, sizeof (struct scsi_sense_data), cdbl,
637 		    60 * 1000);
638 		bcopy(cdb, ccb->csio.cdb_io.cdb_bytes, cdbl);
639 	}
640 
641 	error = cam_periph_runccb(ccb, enc_error, ENC_CFLAGS, ENC_FLAGS, NULL);
642 	if (error) {
643 		if (dptr) {
644 			*dlenp = dlen;
645 		}
646 	} else {
647 		if (dptr) {
648 			if (ccb->ccb_h.func_code == XPT_ATA_IO)
649 				*dlenp = ccb->ataio.resid;
650 			else
651 				*dlenp = ccb->csio.resid;
652 			*dlenp += tdlen - dlen;
653 		}
654 	}
655 	xpt_release_ccb(ccb);
656 	CAM_DEBUG(enc->periph->path, CAM_DEBUG_SUBTRACE,
657 	    ("exiting enc_runcmd: *dlenp = %d\n", *dlenp));
658 	return (error);
659 }
660 
661 void
enc_log(struct enc_softc * enc,const char * fmt,...)662 enc_log(struct enc_softc *enc, const char *fmt, ...)
663 {
664 	va_list ap;
665 
666 	printf("%s%d: ", enc->periph->periph_name, enc->periph->unit_number);
667 	va_start(ap, fmt);
668 	vprintf(fmt, ap);
669 	va_end(ap);
670 }
671 
672 /*
673  * The code after this point runs on many platforms,
674  * so forgive the slightly awkward and nonconforming
675  * appearance.
676  */
677 
678 /*
679  * Is this a device that supports enclosure services?
680  *
681  * It's a a pretty simple ruleset- if it is device type
682  * 0x0D (13), it's an ENCLOSURE device.
683  */
684 
685 #define	SAFTE_START	44
686 #define	SAFTE_END	50
687 #define	SAFTE_LEN	SAFTE_END-SAFTE_START
688 
689 static enctyp
enc_type(struct ccb_getdev * cgd)690 enc_type(struct ccb_getdev *cgd)
691 {
692 	int buflen;
693 	unsigned char *iqd;
694 
695 	if (cgd->protocol == PROTO_SEMB) {
696 		iqd = (unsigned char *)&cgd->ident_data;
697 		if (STRNCMP(iqd + 43, "S-E-S", 5) == 0)
698 			return (ENC_SEMB_SES);
699 		else if (STRNCMP(iqd + 43, "SAF-TE", 6) == 0)
700 			return (ENC_SEMB_SAFT);
701 		return (ENC_NONE);
702 
703 	} else if (cgd->protocol != PROTO_SCSI)
704 		return (ENC_NONE);
705 
706 	iqd = (unsigned char *)&cgd->inq_data;
707 	buflen = min(sizeof(cgd->inq_data),
708 	    SID_ADDITIONAL_LENGTH(&cgd->inq_data));
709 
710 	if ((iqd[0] & 0x1f) == T_ENCLOSURE) {
711 		if ((iqd[2] & 0x7) > 2) {
712 			return (ENC_SES);
713 		} else {
714 			return (ENC_SES_SCSI2);
715 		}
716 		return (ENC_NONE);
717 	}
718 
719 #ifdef	SES_ENABLE_PASSTHROUGH
720 	if ((iqd[6] & 0x40) && (iqd[2] & 0x7) >= 2) {
721 		/*
722 		 * PassThrough Device.
723 		 */
724 		return (ENC_SES_PASSTHROUGH);
725 	}
726 #endif
727 
728 	/*
729 	 * The comparison is short for a reason-
730 	 * some vendors were chopping it short.
731 	 */
732 
733 	if (buflen < SAFTE_END - 2) {
734 		return (ENC_NONE);
735 	}
736 
737 	if (STRNCMP((char *)&iqd[SAFTE_START], "SAF-TE", SAFTE_LEN - 2) == 0) {
738 		return (ENC_SAFT);
739 	}
740 	return (ENC_NONE);
741 }
742 
743 /*================== Enclosure Monitoring/Processing Daemon ==================*/
744 /**
745  * \brief Queue an update request for a given action, if needed.
746  *
747  * \param enc		SES softc to queue the request for.
748  * \param action	Action requested.
749  */
750 void
enc_update_request(enc_softc_t * enc,uint32_t action)751 enc_update_request(enc_softc_t *enc, uint32_t action)
752 {
753 	if ((enc->pending_actions & (0x1 << action)) == 0) {
754 		enc->pending_actions |= (0x1 << action);
755 		ENC_DLOG(enc, "%s: queing requested action %d\n",
756 		    __func__, action);
757 		if (enc->current_action == ENC_UPDATE_NONE)
758 			wakeup(enc->enc_daemon);
759 	} else {
760 		ENC_DLOG(enc, "%s: ignoring requested action %d - "
761 		    "Already queued\n", __func__, action);
762 	}
763 }
764 
765 /**
766  * \brief Invoke the handler of the highest priority pending
767  *	  state in the SES state machine.
768  *
769  * \param enc  The SES instance invoking the state machine.
770  */
771 static void
enc_fsm_step(enc_softc_t * enc)772 enc_fsm_step(enc_softc_t *enc)
773 {
774 	union ccb            *ccb;
775 	uint8_t              *buf;
776 	struct enc_fsm_state *cur_state;
777 	int		      error;
778 	uint32_t	      xfer_len;
779 
780 	ENC_DLOG(enc, "%s enter %p\n", __func__, enc);
781 
782 	enc->current_action   = ffs(enc->pending_actions) - 1;
783 	enc->pending_actions &= ~(0x1 << enc->current_action);
784 
785 	cur_state = &enc->enc_fsm_states[enc->current_action];
786 
787 	buf = NULL;
788 	if (cur_state->buf_size != 0) {
789 		cam_periph_unlock(enc->periph);
790 		buf = malloc(cur_state->buf_size, M_SCSIENC, M_WAITOK|M_ZERO);
791 		cam_periph_lock(enc->periph);
792 	}
793 
794 	error = 0;
795 	ccb   = NULL;
796 	if (cur_state->fill != NULL) {
797 		ccb = cam_periph_getccb(enc->periph, CAM_PRIORITY_NORMAL);
798 
799 		error = cur_state->fill(enc, cur_state, ccb, buf);
800 		if (error != 0)
801 			goto done;
802 
803 		error = cam_periph_runccb(ccb, cur_state->error,
804 					  ENC_CFLAGS,
805 					  ENC_FLAGS|SF_QUIET_IR, NULL);
806 	}
807 
808 	if (ccb != NULL) {
809 		if (ccb->ccb_h.func_code == XPT_ATA_IO)
810 			xfer_len = ccb->ataio.dxfer_len - ccb->ataio.resid;
811 		else
812 			xfer_len = ccb->csio.dxfer_len - ccb->csio.resid;
813 	} else
814 		xfer_len = 0;
815 
816 	cam_periph_unlock(enc->periph);
817 	cur_state->done(enc, cur_state, ccb, &buf, error, xfer_len);
818 	cam_periph_lock(enc->periph);
819 
820 done:
821 	ENC_DLOG(enc, "%s exit - result %d\n", __func__, error);
822 	ENC_FREE_AND_NULL(buf);
823 	if (ccb != NULL)
824 		xpt_release_ccb(ccb);
825 }
826 
827 /**
828  * \invariant Called with cam_periph mutex held.
829  */
830 static void
enc_status_updater(void * arg)831 enc_status_updater(void *arg)
832 {
833 	enc_softc_t *enc;
834 
835 	enc = arg;
836 	if (enc->enc_vec.poll_status != NULL)
837 		enc->enc_vec.poll_status(enc);
838 }
839 
840 static void
enc_daemon(void * arg)841 enc_daemon(void *arg)
842 {
843 	enc_softc_t *enc;
844 
845 	enc = arg;
846 
847 	cam_periph_lock(enc->periph);
848 	while ((enc->enc_flags & ENC_FLAG_SHUTDOWN) == 0) {
849 		if (enc->pending_actions == 0) {
850 			struct intr_config_hook *hook;
851 
852 			/*
853 			 * Reset callout and msleep, or
854 			 * issue timed task completion
855 			 * status command.
856 			 */
857 			enc->current_action = ENC_UPDATE_NONE;
858 
859 			/*
860 			 * We've been through our state machine at least
861 			 * once.  Allow the transition to userland.
862 			 */
863 			hook = &enc->enc_boot_hold_ch;
864 			if (hook->ich_func != NULL) {
865 				config_intrhook_disestablish(hook);
866 				hook->ich_func = NULL;
867 			}
868 
869 			callout_reset(&enc->status_updater, 60*hz,
870 				      enc_status_updater, enc);
871 
872 			cam_periph_sleep(enc->periph, enc->enc_daemon,
873 					 PUSER, "idle", 0);
874 		} else {
875 			enc_fsm_step(enc);
876 		}
877 	}
878 	enc->enc_daemon = NULL;
879 	cam_periph_unlock(enc->periph);
880 	cam_periph_release(enc->periph);
881 	kproc_exit(0);
882 }
883 
884 static int
enc_kproc_init(enc_softc_t * enc)885 enc_kproc_init(enc_softc_t *enc)
886 {
887 	int result;
888 
889 	callout_init_mtx(&enc->status_updater, enc->periph->sim->mtx, 0);
890 
891 	if (cam_periph_acquire(enc->periph) != CAM_REQ_CMP)
892 		return (ENXIO);
893 
894 	result = kproc_create(enc_daemon, enc, &enc->enc_daemon, /*flags*/0,
895 			      /*stackpgs*/0, "enc_daemon%d",
896 			      enc->periph->unit_number);
897 	if (result == 0) {
898 		/* Do an initial load of all page data. */
899 		cam_periph_lock(enc->periph);
900 		enc->enc_vec.poll_status(enc);
901 		cam_periph_unlock(enc->periph);
902 	} else
903 		cam_periph_release(enc->periph);
904 	return (result);
905 }
906 
907 /**
908  * \brief Interrupt configuration hook callback associated with
909  *        enc_boot_hold_ch.
910  *
911  * Since interrupts are always functional at the time of enclosure
912  * configuration, there is nothing to be done when the callback occurs.
913  * This hook is only registered to hold up boot processing while initial
914  * eclosure processing occurs.
915  *
916  * \param arg  The enclosure softc, but currently unused in this callback.
917  */
918 static void
enc_nop_confighook_cb(void * arg __unused)919 enc_nop_confighook_cb(void *arg __unused)
920 {
921 }
922 
923 static cam_status
enc_ctor(struct cam_periph * periph,void * arg)924 enc_ctor(struct cam_periph *periph, void *arg)
925 {
926 	cam_status status = CAM_REQ_CMP_ERR;
927 	int err;
928 	enc_softc_t *enc;
929 	struct ccb_getdev *cgd;
930 	char *tname;
931 
932 	cgd = (struct ccb_getdev *)arg;
933 	if (cgd == NULL) {
934 		printf("enc_ctor: no getdev CCB, can't register device\n");
935 		goto out;
936 	}
937 
938 	enc = ENC_MALLOCZ(sizeof(*enc));
939 	if (enc == NULL) {
940 		printf("enc_ctor: Unable to probe new device. "
941 		       "Unable to allocate enc\n");
942 		goto out;
943 	}
944 	enc->periph = periph;
945 	enc->current_action = ENC_UPDATE_INVALID;
946 
947 	enc->enc_type = enc_type(cgd);
948 	sx_init(&enc->enc_cache_lock, "enccache");
949 
950 	switch (enc->enc_type) {
951 	case ENC_SES:
952 	case ENC_SES_SCSI2:
953 	case ENC_SES_PASSTHROUGH:
954 	case ENC_SEMB_SES:
955 		err = ses_softc_init(enc);
956 		break;
957 	case ENC_SAFT:
958 	case ENC_SEMB_SAFT:
959 		err = safte_softc_init(enc);
960 		break;
961 	case ENC_NONE:
962 	default:
963 		ENC_FREE(enc);
964 		return (CAM_REQ_CMP_ERR);
965 	}
966 
967 	if (err) {
968 		xpt_print(periph->path, "error %d initializing\n", err);
969 		goto out;
970 	}
971 
972 	/*
973 	 * Hold off userland until we have made at least one pass
974 	 * through our state machine so that physical path data is
975 	 * present.
976 	 */
977 	if (enc->enc_vec.poll_status != NULL) {
978 		enc->enc_boot_hold_ch.ich_func = enc_nop_confighook_cb;
979 		enc->enc_boot_hold_ch.ich_arg = enc;
980 		config_intrhook_establish(&enc->enc_boot_hold_ch);
981 	}
982 
983 	/*
984 	 * The softc field is set only once the enc is fully initialized
985 	 * so that we can rely on this field to detect partially
986 	 * initialized periph objects in the AC_FOUND_DEVICE handler.
987 	 */
988 	periph->softc = enc;
989 
990 	cam_periph_unlock(periph);
991 	if (enc->enc_vec.poll_status != NULL) {
992 		err = enc_kproc_init(enc);
993 		if (err) {
994 			xpt_print(periph->path,
995 				  "error %d starting enc_daemon\n", err);
996 			goto out;
997 		}
998 	}
999 
1000 	/*
1001 	 * Acquire a reference to the periph before we create the devfs
1002 	 * instance for it.  We'll release this reference once the devfs
1003 	 * instance has been freed.
1004 	 */
1005 	if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
1006 		xpt_print(periph->path, "%s: lost periph during "
1007 			  "registration!\n", __func__);
1008 		cam_periph_lock(periph);
1009 
1010 		return (CAM_REQ_CMP_ERR);
1011 	}
1012 
1013 	enc->enc_dev = make_dev(&enc_cdevsw, periph->unit_number,
1014 	    UID_ROOT, GID_OPERATOR, 0600, "%s%d",
1015 	    periph->periph_name, periph->unit_number);
1016 
1017 	cam_periph_lock(periph);
1018 	enc->enc_dev->si_drv1 = periph;
1019 
1020 	enc->enc_flags |= ENC_FLAG_INITIALIZED;
1021 
1022 	/*
1023 	 * Add an async callback so that we get notified if this
1024 	 * device goes away.
1025 	 */
1026 	xpt_register_async(AC_LOST_DEVICE, enc_async, periph, periph->path);
1027 
1028 	switch (enc->enc_type) {
1029 	default:
1030 	case ENC_NONE:
1031 		tname = "No ENC device";
1032 		break;
1033 	case ENC_SES_SCSI2:
1034 		tname = "SCSI-2 ENC Device";
1035 		break;
1036 	case ENC_SES:
1037 		tname = "SCSI-3 ENC Device";
1038 		break;
1039         case ENC_SES_PASSTHROUGH:
1040 		tname = "ENC Passthrough Device";
1041 		break;
1042         case ENC_SAFT:
1043 		tname = "SAF-TE Compliant Device";
1044 		break;
1045 	case ENC_SEMB_SES:
1046 		tname = "SEMB SES Device";
1047 		break;
1048 	case ENC_SEMB_SAFT:
1049 		tname = "SEMB SAF-TE Device";
1050 		break;
1051 	}
1052 	xpt_announce_periph(periph, tname);
1053 	status = CAM_REQ_CMP;
1054 
1055 out:
1056 	if (status != CAM_REQ_CMP)
1057 		enc_dtor(periph);
1058 	return (status);
1059 }
1060 
1061