ctl_frontend_internal.c revision 249510
1/*-
2 * Copyright (c) 2004, 2005 Silicon Graphics International Corp.
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.
11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12 *    substantially similar to the "NO WARRANTY" disclaimer below
13 *    ("Disclaimer") and any redistribution must be conditioned upon
14 *    including a substantially similar Disclaimer requirement for further
15 *    binary redistribution.
16 *
17 * NO WARRANTY
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGES.
29 *
30 * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_frontend_internal.c#5 $
31 */
32/*
33 * CTL kernel internal frontend target driver.  This allows kernel-level
34 * clients to send commands into CTL.
35 *
36 * This has elements of a FETD (e.g. it has to set tag numbers, initiator,
37 * port, target, and LUN) and elements of an initiator (LUN discovery and
38 * probing, error recovery, command initiation).  Even though this has some
39 * initiator type elements, this is not intended to be a full fledged
40 * initiator layer.  It is only intended to send a limited number of
41 * commands to a well known target layer.
42 *
43 * To be able to fulfill the role of a full initiator layer, it would need
44 * a whole lot more functionality.
45 *
46 * Author: Ken Merry <ken@FreeBSD.org>
47 *
48 */
49
50#include <sys/cdefs.h>
51__FBSDID("$FreeBSD: stable/9/sys/cam/ctl/ctl_frontend_internal.c 249510 2013-04-15 17:16:12Z trasz $");
52
53#include <sys/param.h>
54#include <sys/systm.h>
55#include <sys/kernel.h>
56#include <sys/types.h>
57#include <sys/malloc.h>
58#include <sys/module.h>
59#include <sys/lock.h>
60#include <sys/mutex.h>
61#include <sys/condvar.h>
62#include <sys/queue.h>
63#include <sys/sbuf.h>
64#include <sys/sysctl.h>
65#include <cam/scsi/scsi_all.h>
66#include <cam/scsi/scsi_da.h>
67#include <cam/ctl/ctl_io.h>
68#include <cam/ctl/ctl.h>
69#include <cam/ctl/ctl_frontend.h>
70#include <cam/ctl/ctl_frontend_internal.h>
71#include <cam/ctl/ctl_backend.h>
72#include <cam/ctl/ctl_ioctl.h>
73#include <cam/ctl/ctl_util.h>
74#include <cam/ctl/ctl_ha.h>
75#include <cam/ctl/ctl_private.h>
76#include <cam/ctl/ctl_mem_pool.h>
77#include <cam/ctl/ctl_debug.h>
78#include <cam/ctl/ctl_scsi_all.h>
79#include <cam/ctl/ctl_error.h>
80
81/*
82 * Task structure:
83 *  - overall metatask, different potential metatask types (e.g. forced
84 *    shutdown, gentle shutdown)
85 *  - forced shutdown metatask:
86 *     - states:  report luns, pending, done?
87 *     - list of luns pending, with the relevant I/O for that lun attached.
88 *       This would allow moving ahead on LUNs with no errors, and going
89 *       into error recovery on LUNs with problems.  Per-LUN states might
90 *       include inquiry, stop/offline, done.
91 *
92 * Use LUN enable for LUN list instead of getting it manually?  We'd still
93 * need inquiry data for each LUN.
94 *
95 * How to handle processor LUN w.r.t. found/stopped counts?
96 */
97#ifdef oldapi
98typedef enum {
99	CFI_TASK_NONE,
100	CFI_TASK_SHUTDOWN,
101	CFI_TASK_STARTUP
102} cfi_tasktype;
103
104struct cfi_task_startstop {
105	int total_luns;
106	int luns_complete;
107	int luns_failed;
108	cfi_cb_t callback;
109	void *callback_arg;
110	/* XXX KDM add more fields here */
111};
112
113union cfi_taskinfo {
114	struct cfi_task_startstop startstop;
115};
116
117struct cfi_metatask {
118	cfi_tasktype		tasktype;
119	cfi_mt_status		status;
120	union cfi_taskinfo	taskinfo;
121	struct ctl_mem_element	*element;
122	void			*cfi_context;
123	STAILQ_ENTRY(cfi_metatask) links;
124};
125#endif
126
127typedef enum {
128	CFI_ERR_RETRY		= 0x000,
129	CFI_ERR_FAIL		= 0x001,
130	CFI_ERR_LUN_RESET	= 0x002,
131	CFI_ERR_MASK		= 0x0ff,
132	CFI_ERR_NO_DECREMENT	= 0x100
133} cfi_error_action;
134
135typedef enum {
136	CFI_ERR_SOFT,
137	CFI_ERR_HARD
138} cfi_error_policy;
139
140typedef enum {
141	CFI_LUN_INQUIRY,
142	CFI_LUN_READCAPACITY,
143	CFI_LUN_READCAPACITY_16,
144	CFI_LUN_READY
145} cfi_lun_state;
146
147struct cfi_lun {
148	struct ctl_id target_id;
149	int lun_id;
150	struct scsi_inquiry_data inq_data;
151	uint64_t num_blocks;
152	uint32_t blocksize;
153	int blocksize_powerof2;
154	uint32_t cur_tag_num;
155	cfi_lun_state state;
156	struct ctl_mem_element *element;
157	struct cfi_softc *softc;
158	STAILQ_HEAD(, cfi_lun_io) io_list;
159	STAILQ_ENTRY(cfi_lun) links;
160};
161
162struct cfi_lun_io {
163	struct cfi_lun *lun;
164	struct cfi_metatask *metatask;
165	cfi_error_policy policy;
166	void (*done_function)(union ctl_io *io);
167	union ctl_io *ctl_io;
168	struct cfi_lun_io *orig_lun_io;
169	STAILQ_ENTRY(cfi_lun_io) links;
170};
171
172typedef enum {
173	CFI_NONE	= 0x00,
174	CFI_ONLINE	= 0x01,
175} cfi_flags;
176
177struct cfi_softc {
178	struct ctl_frontend fe;
179	char fe_name[40];
180	struct mtx lock;
181	cfi_flags flags;
182	STAILQ_HEAD(, cfi_lun) lun_list;
183	STAILQ_HEAD(, cfi_metatask) metatask_list;
184	struct ctl_mem_pool lun_pool;
185	struct ctl_mem_pool metatask_pool;
186};
187
188MALLOC_DEFINE(M_CTL_CFI, "ctlcfi", "CTL CFI");
189
190static struct cfi_softc fetd_internal_softc;
191extern int ctl_disable;
192
193int cfi_init(void);
194void cfi_shutdown(void) __unused;
195static void cfi_online(void *arg);
196static void cfi_offline(void *arg);
197static int cfi_targ_enable(void *arg, struct ctl_id targ_id);
198static int cfi_targ_disable(void *arg, struct ctl_id targ_id);
199static int cfi_lun_enable(void *arg, struct ctl_id target_id, int lun_id);
200static int cfi_lun_disable(void *arg, struct ctl_id target_id, int lun_id);
201static void cfi_datamove(union ctl_io *io);
202static cfi_error_action cfi_checkcond_parse(union ctl_io *io,
203					    struct cfi_lun_io *lun_io);
204static cfi_error_action cfi_error_parse(union ctl_io *io,
205					struct cfi_lun_io *lun_io);
206static void cfi_init_io(union ctl_io *io, struct cfi_lun *lun,
207			struct cfi_metatask *metatask, cfi_error_policy policy,
208			int retries, struct cfi_lun_io *orig_lun_io,
209			void (*done_function)(union ctl_io *io));
210static void cfi_done(union ctl_io *io);
211static void cfi_lun_probe_done(union ctl_io *io);
212static void cfi_lun_probe(struct cfi_lun *lun, int have_lock);
213static void cfi_metatask_done(struct cfi_softc *softc,
214			      struct cfi_metatask *metatask);
215static void cfi_metatask_bbr_errorparse(struct cfi_metatask *metatask,
216					union ctl_io *io);
217static void cfi_metatask_io_done(union ctl_io *io);
218static void cfi_err_recovery_done(union ctl_io *io);
219static void cfi_lun_io_done(union ctl_io *io);
220
221static int cfi_module_event_handler(module_t, int /*modeventtype_t*/, void *);
222
223static moduledata_t cfi_moduledata = {
224	"ctlcfi",
225	cfi_module_event_handler,
226	NULL
227};
228
229DECLARE_MODULE(ctlcfi, cfi_moduledata, SI_SUB_CONFIGURE, SI_ORDER_FOURTH);
230MODULE_VERSION(ctlcfi, 1);
231MODULE_DEPEND(ctlcfi, ctl, 1, 1, 1);
232
233int
234cfi_init(void)
235{
236	struct cfi_softc *softc;
237	struct ctl_frontend *fe;
238	int retval;
239
240	softc = &fetd_internal_softc;
241
242	fe = &softc->fe;
243
244	retval = 0;
245
246	/* If we're disabled, don't initialize */
247	if (ctl_disable != 0)
248		return (0);
249
250	if (sizeof(struct cfi_lun_io) > CTL_PORT_PRIV_SIZE) {
251		printf("%s: size of struct cfi_lun_io %zd > "
252		       "CTL_PORT_PRIV_SIZE %d\n", __func__,
253		       sizeof(struct cfi_lun_io),
254		       CTL_PORT_PRIV_SIZE);
255	}
256	memset(softc, 0, sizeof(softc));
257
258	mtx_init(&softc->lock, "CTL frontend mutex", NULL, MTX_DEF);
259	softc->flags |= CTL_FLAG_MASTER_SHELF;
260
261	STAILQ_INIT(&softc->lun_list);
262	STAILQ_INIT(&softc->metatask_list);
263	sprintf(softc->fe_name, "CTL internal");
264	fe->port_type = CTL_PORT_INTERNAL;
265	fe->num_requested_ctl_io = 100;
266	fe->port_name = softc->fe_name;
267	fe->port_online = cfi_online;
268	fe->port_offline = cfi_offline;
269	fe->onoff_arg = softc;
270	fe->targ_enable = cfi_targ_enable;
271	fe->targ_disable = cfi_targ_disable;
272	fe->lun_enable = cfi_lun_enable;
273	fe->lun_disable = cfi_lun_disable;
274	fe->targ_lun_arg = softc;
275	fe->fe_datamove = cfi_datamove;
276	fe->fe_done = cfi_done;
277	fe->max_targets = 15;
278	fe->max_target_id = 15;
279
280	if (ctl_frontend_register(fe, (softc->flags & CTL_FLAG_MASTER_SHELF)) != 0)
281	{
282		printf("%s: internal frontend registration failed\n", __func__);
283		retval = 1;
284		goto bailout;
285	}
286
287	if (ctl_init_mem_pool(&softc->lun_pool,
288			      sizeof(struct cfi_lun),
289			      CTL_MEM_POOL_PERM_GROW, /*grow_inc*/ 3,
290			      /* initial_pool_size */ CTL_MAX_LUNS) != 0) {
291		printf("%s: can't initialize LUN memory pool\n", __func__);
292		retval = 1;
293		goto bailout_error;
294	}
295
296	if (ctl_init_mem_pool(&softc->metatask_pool,
297			      sizeof(struct cfi_metatask),
298			      CTL_MEM_POOL_PERM_GROW, /*grow_inc*/ 3,
299			      /*initial_pool_size*/ 10) != 0) {
300		printf("%s: can't initialize metatask memory pool\n", __func__);
301		retval = 2;
302		goto bailout_error;
303	}
304bailout:
305
306	return (0);
307
308bailout_error:
309
310	switch (retval) {
311	case 3:
312		ctl_shrink_mem_pool(&softc->metatask_pool);
313		/* FALLTHROUGH */
314	case 2:
315		ctl_shrink_mem_pool(&softc->lun_pool);
316		/* FALLTHROUGH */
317	case 1:
318		ctl_frontend_deregister(fe);
319		break;
320	default:
321		break;
322	}
323
324	return (ENOMEM);
325}
326
327void
328cfi_shutdown(void)
329{
330	struct cfi_softc *softc;
331
332	softc = &fetd_internal_softc;
333
334	/*
335	 * XXX KDM need to clear out any I/O pending on each LUN.
336	 */
337	if (ctl_frontend_deregister(&softc->fe) != 0)
338		printf("%s: ctl_frontend_deregister() failed\n", __func__);
339
340	if (ctl_shrink_mem_pool(&softc->lun_pool) != 0)
341		printf("%s: error shrinking LUN pool\n", __func__);
342
343	if (ctl_shrink_mem_pool(&softc->metatask_pool) != 0)
344		printf("%s: error shrinking LUN pool\n", __func__);
345}
346
347static int
348cfi_module_event_handler(module_t mod, int what, void *arg)
349{
350
351	switch (what) {
352	case MOD_LOAD:
353		return (cfi_init());
354	case MOD_UNLOAD:
355		return (EBUSY);
356	default:
357		return (EOPNOTSUPP);
358	}
359}
360
361static void
362cfi_online(void *arg)
363{
364	struct cfi_softc *softc;
365	struct cfi_lun *lun;
366
367	softc = (struct cfi_softc *)arg;
368
369	softc->flags |= CFI_ONLINE;
370
371	/*
372	 * Go through and kick off the probe for each lun.  Should we check
373	 * the LUN flags here to determine whether or not to probe it?
374	 */
375	mtx_lock(&softc->lock);
376	STAILQ_FOREACH(lun, &softc->lun_list, links)
377		cfi_lun_probe(lun, /*have_lock*/ 1);
378	mtx_unlock(&softc->lock);
379}
380
381static void
382cfi_offline(void *arg)
383{
384	struct cfi_softc *softc;
385
386	softc = (struct cfi_softc *)arg;
387
388	softc->flags &= ~CFI_ONLINE;
389}
390
391static int
392cfi_targ_enable(void *arg, struct ctl_id targ_id)
393{
394	return (0);
395}
396
397static int
398cfi_targ_disable(void *arg, struct ctl_id targ_id)
399{
400	return (0);
401}
402
403static int
404cfi_lun_enable(void *arg, struct ctl_id target_id, int lun_id)
405{
406	struct ctl_mem_element *element;
407	struct cfi_softc *softc;
408	struct cfi_lun *lun;
409	int found;
410
411	softc = (struct cfi_softc *)arg;
412
413	found = 0;
414	mtx_lock(&softc->lock);
415	STAILQ_FOREACH(lun, &softc->lun_list, links) {
416		if ((lun->target_id.id == target_id.id)
417		 && (lun->lun_id == lun_id)) {
418			found = 1;
419			break;
420		}
421	}
422	mtx_unlock(&softc->lock);
423
424	/*
425	 * If we already have this target/LUN, there is no reason to add
426	 * it to our lists again.
427	 */
428	if (found != 0)
429		return (0);
430
431	element = ctl_alloc_mem_element(&softc->lun_pool, /*can_wait*/ 0);
432
433	if (element == NULL) {
434		printf("%s: unable to allocate LUN structure\n", __func__);
435		return (1);
436	}
437
438	lun = (struct cfi_lun *)element->bytes;
439
440	lun->element = element;
441	lun->target_id = target_id;
442	lun->lun_id = lun_id;
443	lun->cur_tag_num = 0;
444	lun->state = CFI_LUN_INQUIRY;
445	lun->softc = softc;
446	STAILQ_INIT(&lun->io_list);
447
448	mtx_lock(&softc->lock);
449	STAILQ_INSERT_TAIL(&softc->lun_list, lun, links);
450	mtx_unlock(&softc->lock);
451
452	cfi_lun_probe(lun, /*have_lock*/ 0);
453
454	return (0);
455}
456
457static int
458cfi_lun_disable(void *arg, struct ctl_id target_id, int lun_id)
459{
460	struct cfi_softc *softc;
461	struct cfi_lun *lun;
462	int found;
463
464	softc = (struct cfi_softc *)arg;
465
466	found = 0;
467
468	/*
469	 * XXX KDM need to do an invalidate and then a free when any
470	 * pending I/O has completed.  Or do we?  CTL won't free a LUN
471	 * while any I/O is pending.  So we won't get this notification
472	 * unless any I/O we have pending on a LUN has completed.
473	 */
474	mtx_lock(&softc->lock);
475	STAILQ_FOREACH(lun, &softc->lun_list, links) {
476		if ((lun->target_id.id == target_id.id)
477		 && (lun->lun_id == lun_id)) {
478			found = 1;
479			break;
480		}
481	}
482	if (found != 0)
483		STAILQ_REMOVE(&softc->lun_list, lun, cfi_lun, links);
484
485	mtx_unlock(&softc->lock);
486
487	if (found == 0) {
488		printf("%s: can't find target %ju lun %d\n", __func__,
489		       (uintmax_t)target_id.id, lun_id);
490		return (1);
491	}
492
493	ctl_free_mem_element(lun->element);
494
495	return (0);
496}
497
498/*
499 * XXX KDM run this inside a thread, or inside the caller's context?
500 */
501static void
502cfi_datamove(union ctl_io *io)
503{
504	struct ctl_sg_entry *ext_sglist, *kern_sglist;
505	struct ctl_sg_entry ext_entry, kern_entry;
506	int ext_sglen, ext_sg_entries, kern_sg_entries;
507	int ext_sg_start, ext_offset;
508	int len_to_copy, len_copied;
509	int kern_watermark, ext_watermark;
510	int ext_sglist_malloced;
511	struct ctl_scsiio *ctsio;
512	int i, j;
513
514	ext_sglist_malloced = 0;
515	ext_sg_start = 0;
516	ext_offset = 0;
517	ext_sglist = NULL;
518
519	CTL_DEBUG_PRINT(("%s\n", __func__));
520
521	ctsio = &io->scsiio;
522
523	/*
524	 * If this is the case, we're probably doing a BBR read and don't
525	 * actually need to transfer the data.  This will effectively
526	 * bit-bucket the data.
527	 */
528	if (ctsio->ext_data_ptr == NULL)
529		goto bailout;
530
531	/*
532	 * To simplify things here, if we have a single buffer, stick it in
533	 * a S/G entry and just make it a single entry S/G list.
534	 */
535	if (ctsio->io_hdr.flags & CTL_FLAG_EDPTR_SGLIST) {
536		int len_seen;
537
538		ext_sglen = ctsio->ext_sg_entries * sizeof(*ext_sglist);
539
540		/*
541		 * XXX KDM GFP_KERNEL, don't know what the caller's context
542		 * is.  Need to figure that out.
543		 */
544		ext_sglist = (struct ctl_sg_entry *)malloc(ext_sglen, M_CTL_CFI,
545							   M_WAITOK);
546		if (ext_sglist == NULL) {
547			ctl_set_internal_failure(ctsio,
548						 /*sks_valid*/ 0,
549						 /*retry_count*/ 0);
550			return;
551		}
552		ext_sglist_malloced = 1;
553		if (memcpy(ext_sglist, ctsio->ext_data_ptr, ext_sglen) != 0) {
554			ctl_set_internal_failure(ctsio,
555						 /*sks_valid*/ 0,
556						 /*retry_count*/ 0);
557			goto bailout;
558		}
559		ext_sg_entries = ctsio->ext_sg_entries;
560		len_seen = 0;
561		for (i = 0; i < ext_sg_entries; i++) {
562			if ((len_seen + ext_sglist[i].len) >=
563			     ctsio->ext_data_filled) {
564				ext_sg_start = i;
565				ext_offset = ctsio->ext_data_filled - len_seen;
566				break;
567			}
568			len_seen += ext_sglist[i].len;
569		}
570	} else {
571		ext_sglist = &ext_entry;
572		ext_sglist->addr = ctsio->ext_data_ptr;
573		ext_sglist->len = ctsio->ext_data_len;
574		ext_sg_entries = 1;
575		ext_sg_start = 0;
576		ext_offset = ctsio->ext_data_filled;
577	}
578
579	if (ctsio->kern_sg_entries > 0) {
580		kern_sglist = (struct ctl_sg_entry *)ctsio->kern_data_ptr;
581		kern_sg_entries = ctsio->kern_sg_entries;
582	} else {
583		kern_sglist = &kern_entry;
584		kern_sglist->addr = ctsio->kern_data_ptr;
585		kern_sglist->len = ctsio->kern_data_len;
586		kern_sg_entries = 1;
587	}
588
589
590	kern_watermark = 0;
591	ext_watermark = ext_offset;
592	len_copied = 0;
593	for (i = ext_sg_start, j = 0;
594	     i < ext_sg_entries && j < kern_sg_entries;) {
595		uint8_t *ext_ptr, *kern_ptr;
596
597		len_to_copy = ctl_min(ext_sglist[i].len - ext_watermark,
598				      kern_sglist[j].len - kern_watermark);
599
600		ext_ptr = (uint8_t *)ext_sglist[i].addr;
601		ext_ptr = ext_ptr + ext_watermark;
602		if (io->io_hdr.flags & CTL_FLAG_BUS_ADDR) {
603			/*
604			 * XXX KDM fix this!
605			 */
606			panic("need to implement bus address support");
607#if 0
608			kern_ptr = bus_to_virt(kern_sglist[j].addr);
609#endif
610		} else
611			kern_ptr = (uint8_t *)kern_sglist[j].addr;
612		kern_ptr = kern_ptr + kern_watermark;
613
614		kern_watermark += len_to_copy;
615		ext_watermark += len_to_copy;
616
617		if ((ctsio->io_hdr.flags & CTL_FLAG_DATA_MASK) ==
618		     CTL_FLAG_DATA_IN) {
619			CTL_DEBUG_PRINT(("%s: copying %d bytes to user\n",
620					 __func__, len_to_copy));
621			CTL_DEBUG_PRINT(("%s: from %p to %p\n", __func__,
622					 kern_ptr, ext_ptr));
623			memcpy(ext_ptr, kern_ptr, len_to_copy);
624		} else {
625			CTL_DEBUG_PRINT(("%s: copying %d bytes from user\n",
626					 __func__, len_to_copy));
627			CTL_DEBUG_PRINT(("%s: from %p to %p\n", __func__,
628					 ext_ptr, kern_ptr));
629			memcpy(kern_ptr, ext_ptr, len_to_copy);
630		}
631
632		len_copied += len_to_copy;
633
634		if (ext_sglist[i].len == ext_watermark) {
635			i++;
636			ext_watermark = 0;
637		}
638
639		if (kern_sglist[j].len == kern_watermark) {
640			j++;
641			kern_watermark = 0;
642		}
643	}
644
645	ctsio->ext_data_filled += len_copied;
646
647	CTL_DEBUG_PRINT(("%s: ext_sg_entries: %d, kern_sg_entries: %d\n",
648			 __func__, ext_sg_entries, kern_sg_entries));
649	CTL_DEBUG_PRINT(("%s: ext_data_len = %d, kern_data_len = %d\n",
650			 __func__, ctsio->ext_data_len, ctsio->kern_data_len));
651
652
653	/* XXX KDM set residual?? */
654bailout:
655
656	if (ext_sglist_malloced != 0)
657		free(ext_sglist, M_CTL_CFI);
658
659	io->scsiio.be_move_done(io);
660
661	return;
662}
663
664/*
665 * For any sort of check condition, busy, etc., we just retry.  We do not
666 * decrement the retry count for unit attention type errors.  These are
667 * normal, and we want to save the retry count for "real" errors.  Otherwise,
668 * we could end up with situations where a command will succeed in some
669 * situations and fail in others, depending on whether a unit attention is
670 * pending.  Also, some of our error recovery actions, most notably the
671 * LUN reset action, will cause a unit attention.
672 *
673 * We can add more detail here later if necessary.
674 */
675static cfi_error_action
676cfi_checkcond_parse(union ctl_io *io, struct cfi_lun_io *lun_io)
677{
678	cfi_error_action error_action;
679	int error_code, sense_key, asc, ascq;
680
681	/*
682	 * Default to retrying the command.
683	 */
684	error_action = CFI_ERR_RETRY;
685
686	scsi_extract_sense_len(&io->scsiio.sense_data,
687			       io->scsiio.sense_len,
688			       &error_code,
689			       &sense_key,
690			       &asc,
691			       &ascq,
692			       /*show_errors*/ 1);
693
694	switch (error_code) {
695	case SSD_DEFERRED_ERROR:
696	case SSD_DESC_DEFERRED_ERROR:
697		error_action |= CFI_ERR_NO_DECREMENT;
698		break;
699	case SSD_CURRENT_ERROR:
700	case SSD_DESC_CURRENT_ERROR:
701	default: {
702		switch (sense_key) {
703		case SSD_KEY_UNIT_ATTENTION:
704			error_action |= CFI_ERR_NO_DECREMENT;
705			break;
706		case SSD_KEY_HARDWARE_ERROR:
707			/*
708			 * This is our generic "something bad happened"
709			 * error code.  It often isn't recoverable.
710			 */
711			if ((asc == 0x44) && (ascq == 0x00))
712				error_action = CFI_ERR_FAIL;
713			break;
714		case SSD_KEY_NOT_READY:
715			/*
716			 * If the LUN is powered down, there likely isn't
717			 * much point in retrying right now.
718			 */
719			if ((asc == 0x04) && (ascq == 0x02))
720				error_action = CFI_ERR_FAIL;
721			/*
722			 * If the LUN is offline, there probably isn't much
723			 * point in retrying, either.
724			 */
725			if ((asc == 0x04) && (ascq == 0x03))
726				error_action = CFI_ERR_FAIL;
727			break;
728		}
729	}
730	}
731
732	return (error_action);
733}
734
735static cfi_error_action
736cfi_error_parse(union ctl_io *io, struct cfi_lun_io *lun_io)
737{
738	cfi_error_action error_action;
739
740	error_action = CFI_ERR_RETRY;
741
742	switch (io->io_hdr.io_type) {
743	case CTL_IO_SCSI:
744		switch (io->io_hdr.status & CTL_STATUS_MASK) {
745		case CTL_SCSI_ERROR:
746			switch (io->scsiio.scsi_status) {
747			case SCSI_STATUS_RESERV_CONFLICT:
748				/*
749				 * For a reservation conflict, we'll usually
750				 * want the hard error recovery policy, so
751				 * we'll reset the LUN.
752				 */
753				if (lun_io->policy == CFI_ERR_HARD)
754					error_action =
755						CFI_ERR_LUN_RESET;
756				else
757					error_action =
758						CFI_ERR_RETRY;
759				break;
760			case SCSI_STATUS_CHECK_COND:
761			default:
762				error_action = cfi_checkcond_parse(io, lun_io);
763				break;
764			}
765			break;
766		default:
767			error_action = CFI_ERR_RETRY;
768			break;
769		}
770		break;
771	case CTL_IO_TASK:
772		/*
773		 * In theory task management commands shouldn't fail...
774		 */
775		error_action = CFI_ERR_RETRY;
776		break;
777	default:
778		printf("%s: invalid ctl_io type %d\n", __func__,
779		       io->io_hdr.io_type);
780		panic("%s: invalid ctl_io type %d\n", __func__,
781		      io->io_hdr.io_type);
782		break;
783	}
784
785	return (error_action);
786}
787
788static void
789cfi_init_io(union ctl_io *io, struct cfi_lun *lun,
790	    struct cfi_metatask *metatask, cfi_error_policy policy, int retries,
791	    struct cfi_lun_io *orig_lun_io,
792	    void (*done_function)(union ctl_io *io))
793{
794	struct cfi_lun_io *lun_io;
795
796	io->io_hdr.nexus.initid.id = 7;
797	io->io_hdr.nexus.targ_port = lun->softc->fe.targ_port;
798	io->io_hdr.nexus.targ_target.id = lun->target_id.id;
799	io->io_hdr.nexus.targ_lun = lun->lun_id;
800	io->io_hdr.retries = retries;
801	lun_io = (struct cfi_lun_io *)io->io_hdr.port_priv;
802	io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = lun_io;
803	lun_io->lun = lun;
804	lun_io->metatask = metatask;
805	lun_io->ctl_io = io;
806	lun_io->policy = policy;
807	lun_io->orig_lun_io = orig_lun_io;
808	lun_io->done_function = done_function;
809	/*
810	 * We only set the tag number for SCSI I/Os.  For task management
811	 * commands, the tag number is only really needed for aborts, so
812	 * the caller can set it if necessary.
813	 */
814	switch (io->io_hdr.io_type) {
815	case CTL_IO_SCSI:
816		io->scsiio.tag_num = lun->cur_tag_num++;
817		break;
818	case CTL_IO_TASK:
819	default:
820		break;
821	}
822}
823
824static void
825cfi_done(union ctl_io *io)
826{
827	struct cfi_lun_io *lun_io;
828	struct cfi_softc *softc;
829	struct cfi_lun *lun;
830
831	lun_io = (struct cfi_lun_io *)
832		io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
833
834	lun = lun_io->lun;
835	softc = lun->softc;
836
837	/*
838	 * Very minimal retry logic.  We basically retry if we got an error
839	 * back, and the retry count is greater than 0.  If we ever want
840	 * more sophisticated initiator type behavior, the CAM error
841	 * recovery code in ../common might be helpful.
842	 */
843	if (((io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS)
844	 && (io->io_hdr.retries > 0)) {
845		ctl_io_status old_status;
846		cfi_error_action error_action;
847
848		error_action = cfi_error_parse(io, lun_io);
849
850		switch (error_action & CFI_ERR_MASK) {
851		case CFI_ERR_FAIL:
852			goto done;
853			break; /* NOTREACHED */
854		case CFI_ERR_LUN_RESET: {
855			union ctl_io *new_io;
856			struct cfi_lun_io *new_lun_io;
857
858			new_io = ctl_alloc_io(softc->fe.ctl_pool_ref);
859			if (new_io == NULL) {
860				printf("%s: unable to allocate ctl_io for "
861				       "error recovery\n", __func__);
862				goto done;
863			}
864			ctl_zero_io(new_io);
865
866			new_io->io_hdr.io_type = CTL_IO_TASK;
867			new_io->taskio.task_action = CTL_TASK_LUN_RESET;
868
869			cfi_init_io(new_io,
870				    /*lun*/ lun_io->lun,
871				    /*metatask*/ NULL,
872				    /*policy*/ CFI_ERR_SOFT,
873				    /*retries*/ 0,
874				    /*orig_lun_io*/lun_io,
875				    /*done_function*/ cfi_err_recovery_done);
876
877
878			new_lun_io = (struct cfi_lun_io *)
879				new_io->io_hdr.port_priv;
880
881			mtx_lock(&lun->softc->lock);
882			STAILQ_INSERT_TAIL(&lun->io_list, new_lun_io, links);
883			mtx_unlock(&lun->softc->lock);
884
885			io = new_io;
886			break;
887		}
888		case CFI_ERR_RETRY:
889		default:
890			if ((error_action & CFI_ERR_NO_DECREMENT) == 0)
891				io->io_hdr.retries--;
892			break;
893		}
894
895		old_status = io->io_hdr.status;
896		io->io_hdr.status = CTL_STATUS_NONE;
897#if 0
898		io->io_hdr.flags &= ~CTL_FLAG_ALREADY_DONE;
899#endif
900		io->io_hdr.flags &= ~CTL_FLAG_ABORT;
901		io->io_hdr.flags &= ~CTL_FLAG_SENT_2OTHER_SC;
902
903		if (ctl_queue(io) != CTL_RETVAL_COMPLETE) {
904			printf("%s: error returned from ctl_queue()!\n",
905			       __func__);
906			io->io_hdr.status = old_status;
907		} else
908			return;
909	}
910done:
911	lun_io->done_function(io);
912}
913
914static void
915cfi_lun_probe_done(union ctl_io *io)
916{
917	struct cfi_lun *lun;
918	struct cfi_lun_io *lun_io;
919
920	lun_io = (struct cfi_lun_io *)
921		io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
922	lun = lun_io->lun;
923
924	switch (lun->state) {
925	case CFI_LUN_INQUIRY: {
926		if ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS) {
927			/* print out something here?? */
928			printf("%s: LUN %d probe failed because inquiry "
929			       "failed\n", __func__, lun->lun_id);
930			ctl_io_error_print(io, NULL);
931		} else {
932
933			if (SID_TYPE(&lun->inq_data) != T_DIRECT) {
934				char path_str[40];
935
936				lun->state = CFI_LUN_READY;
937				ctl_scsi_path_string(io, path_str,
938						     sizeof(path_str));
939				printf("%s", path_str);
940				scsi_print_inquiry(&lun->inq_data);
941			} else {
942				lun->state = CFI_LUN_READCAPACITY;
943				cfi_lun_probe(lun, /*have_lock*/ 0);
944			}
945		}
946		mtx_lock(&lun->softc->lock);
947		STAILQ_REMOVE(&lun->io_list, lun_io, cfi_lun_io, links);
948		mtx_unlock(&lun->softc->lock);
949		ctl_free_io(io);
950		break;
951	}
952	case CFI_LUN_READCAPACITY:
953	case CFI_LUN_READCAPACITY_16: {
954		uint64_t maxlba;
955		uint32_t blocksize;
956
957		maxlba = 0;
958		blocksize = 0;
959
960		if ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS) {
961			printf("%s: LUN %d probe failed because READ CAPACITY "
962			       "failed\n", __func__, lun->lun_id);
963			ctl_io_error_print(io, NULL);
964		} else {
965
966			if (lun->state == CFI_LUN_READCAPACITY) {
967				struct scsi_read_capacity_data *rdcap;
968
969				rdcap = (struct scsi_read_capacity_data *)
970					io->scsiio.ext_data_ptr;
971
972				maxlba = scsi_4btoul(rdcap->addr);
973				blocksize = scsi_4btoul(rdcap->length);
974				if (blocksize == 0) {
975					printf("%s: LUN %d has invalid "
976					       "blocksize 0, probe aborted\n",
977					       __func__, lun->lun_id);
978				} else if (maxlba == 0xffffffff) {
979					lun->state = CFI_LUN_READCAPACITY_16;
980					cfi_lun_probe(lun, /*have_lock*/ 0);
981				} else
982					lun->state = CFI_LUN_READY;
983			} else {
984				struct scsi_read_capacity_data_long *rdcap_long;
985
986				rdcap_long = (struct
987					scsi_read_capacity_data_long *)
988					io->scsiio.ext_data_ptr;
989				maxlba = scsi_8btou64(rdcap_long->addr);
990				blocksize = scsi_4btoul(rdcap_long->length);
991
992				if (blocksize == 0) {
993					printf("%s: LUN %d has invalid "
994					       "blocksize 0, probe aborted\n",
995					       __func__, lun->lun_id);
996				} else
997					lun->state = CFI_LUN_READY;
998			}
999		}
1000
1001		if (lun->state == CFI_LUN_READY) {
1002			char path_str[40];
1003
1004			lun->num_blocks = maxlba + 1;
1005			lun->blocksize = blocksize;
1006
1007			/*
1008			 * If this is true, the blocksize is a power of 2.
1009			 * We already checked for 0 above.
1010			 */
1011			if (((blocksize - 1) & blocksize) == 0) {
1012				int i;
1013
1014				for (i = 0; i < 32; i++) {
1015					if ((blocksize & (1 << i)) != 0) {
1016						lun->blocksize_powerof2 = i;
1017						break;
1018					}
1019				}
1020			}
1021			ctl_scsi_path_string(io, path_str,sizeof(path_str));
1022			printf("%s", path_str);
1023			scsi_print_inquiry(&lun->inq_data);
1024			printf("%s %ju blocks, blocksize %d\n", path_str,
1025			       (uintmax_t)maxlba + 1, blocksize);
1026		}
1027		mtx_lock(&lun->softc->lock);
1028		STAILQ_REMOVE(&lun->io_list, lun_io, cfi_lun_io, links);
1029		mtx_unlock(&lun->softc->lock);
1030		free(io->scsiio.ext_data_ptr, M_CTL_CFI);
1031		ctl_free_io(io);
1032		break;
1033	}
1034	case CFI_LUN_READY:
1035	default:
1036		mtx_lock(&lun->softc->lock);
1037		/* How did we get here?? */
1038		STAILQ_REMOVE(&lun->io_list, lun_io, cfi_lun_io, links);
1039		mtx_unlock(&lun->softc->lock);
1040		ctl_free_io(io);
1041		break;
1042	}
1043}
1044
1045static void
1046cfi_lun_probe(struct cfi_lun *lun, int have_lock)
1047{
1048
1049	if (have_lock == 0)
1050		mtx_lock(&lun->softc->lock);
1051	if ((lun->softc->flags & CFI_ONLINE) == 0) {
1052		if (have_lock == 0)
1053			mtx_unlock(&lun->softc->lock);
1054		return;
1055	}
1056	if (have_lock == 0)
1057		mtx_unlock(&lun->softc->lock);
1058
1059	switch (lun->state) {
1060	case CFI_LUN_INQUIRY: {
1061		struct cfi_lun_io *lun_io;
1062		union ctl_io *io;
1063
1064		io = ctl_alloc_io(lun->softc->fe.ctl_pool_ref);
1065		if (io == NULL) {
1066			printf("%s: unable to alloc ctl_io for target %ju "
1067			       "lun %d probe\n", __func__,
1068			       (uintmax_t)lun->target_id.id, lun->lun_id);
1069			return;
1070		}
1071		ctl_scsi_inquiry(io,
1072				 /*data_ptr*/(uint8_t *)&lun->inq_data,
1073				 /*data_len*/ sizeof(lun->inq_data),
1074				 /*byte2*/ 0,
1075				 /*page_code*/ 0,
1076				 /*tag_type*/ CTL_TAG_SIMPLE,
1077				 /*control*/ 0);
1078
1079		cfi_init_io(io,
1080			    /*lun*/ lun,
1081			    /*metatask*/ NULL,
1082			    /*policy*/ CFI_ERR_SOFT,
1083			    /*retries*/ 5,
1084			    /*orig_lun_io*/ NULL,
1085			    /*done_function*/
1086			    cfi_lun_probe_done);
1087
1088		lun_io = (struct cfi_lun_io *)io->io_hdr.port_priv;
1089
1090		if (have_lock == 0)
1091			mtx_lock(&lun->softc->lock);
1092		STAILQ_INSERT_TAIL(&lun->io_list, lun_io, links);
1093		if (have_lock == 0)
1094			mtx_unlock(&lun->softc->lock);
1095
1096		if (ctl_queue(io) != CTL_RETVAL_COMPLETE) {
1097			printf("%s: error returned from ctl_queue()!\n",
1098			       __func__);
1099			STAILQ_REMOVE(&lun->io_list, lun_io,
1100				      cfi_lun_io, links);
1101			ctl_free_io(io);
1102		}
1103		break;
1104	}
1105	case CFI_LUN_READCAPACITY:
1106	case CFI_LUN_READCAPACITY_16: {
1107		struct cfi_lun_io *lun_io;
1108		uint8_t *dataptr;
1109		union ctl_io *io;
1110
1111		io = ctl_alloc_io(lun->softc->fe.ctl_pool_ref);
1112		if (io == NULL) {
1113			printf("%s: unable to alloc ctl_io for target %ju "
1114			       "lun %d probe\n", __func__,
1115			       (uintmax_t)lun->target_id.id, lun->lun_id);
1116			return;
1117		}
1118
1119		dataptr = malloc(sizeof(struct scsi_read_capacity_data_long),
1120				 M_CTL_CFI, M_NOWAIT);
1121		if (dataptr == NULL) {
1122			printf("%s: unable to allocate SCSI read capacity "
1123			       "buffer for target %ju lun %d\n", __func__,
1124			       (uintmax_t)lun->target_id.id, lun->lun_id);
1125			return;
1126		}
1127		if (lun->state == CFI_LUN_READCAPACITY) {
1128			ctl_scsi_read_capacity(io,
1129				/*data_ptr*/ dataptr,
1130				/*data_len*/
1131				sizeof(struct scsi_read_capacity_data_long),
1132				/*addr*/ 0,
1133				/*reladr*/ 0,
1134				/*pmi*/ 0,
1135				/*tag_type*/ CTL_TAG_SIMPLE,
1136				/*control*/ 0);
1137		} else {
1138			ctl_scsi_read_capacity_16(io,
1139				/*data_ptr*/ dataptr,
1140				/*data_len*/
1141				sizeof(struct scsi_read_capacity_data_long),
1142				/*addr*/ 0,
1143				/*reladr*/ 0,
1144				/*pmi*/ 0,
1145				/*tag_type*/ CTL_TAG_SIMPLE,
1146				/*control*/ 0);
1147		}
1148		cfi_init_io(io,
1149			    /*lun*/ lun,
1150			    /*metatask*/ NULL,
1151			    /*policy*/ CFI_ERR_SOFT,
1152			    /*retries*/ 7,
1153			    /*orig_lun_io*/ NULL,
1154			    /*done_function*/ cfi_lun_probe_done);
1155
1156		lun_io = (struct cfi_lun_io *)io->io_hdr.port_priv;
1157
1158		if (have_lock == 0)
1159			mtx_lock(&lun->softc->lock);
1160		STAILQ_INSERT_TAIL(&lun->io_list, lun_io, links);
1161		if (have_lock == 0)
1162			mtx_unlock(&lun->softc->lock);
1163
1164		if (ctl_queue(io) != CTL_RETVAL_COMPLETE) {
1165			printf("%s: error returned from ctl_queue()!\n",
1166			       __func__);
1167			STAILQ_REMOVE(&lun->io_list, lun_io,
1168				      cfi_lun_io, links);
1169			free(dataptr, M_CTL_CFI);
1170			ctl_free_io(io);
1171		}
1172		break;
1173	}
1174	case CFI_LUN_READY:
1175	default:
1176		/* Why were we called? */
1177		break;
1178	}
1179}
1180
1181static void
1182cfi_metatask_done(struct cfi_softc *softc, struct cfi_metatask *metatask)
1183{
1184	mtx_lock(&softc->lock);
1185	STAILQ_REMOVE(&softc->metatask_list, metatask, cfi_metatask, links);
1186	mtx_unlock(&softc->lock);
1187
1188	/*
1189	 * Return status to the caller.  Caller allocated storage, and is
1190	 * responsible for calling cfi_free_metatask to release it once
1191	 * they've seen the status.
1192	 */
1193	metatask->callback(metatask->callback_arg, metatask);
1194}
1195
1196static void
1197cfi_metatask_bbr_errorparse(struct cfi_metatask *metatask, union ctl_io *io)
1198{
1199	int error_code, sense_key, asc, ascq;
1200
1201	if (metatask->tasktype != CFI_TASK_BBRREAD)
1202		return;
1203
1204	if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) {
1205		metatask->status = CFI_MT_SUCCESS;
1206		metatask->taskinfo.bbrread.status = CFI_BBR_SUCCESS;
1207		return;
1208	}
1209
1210	if ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_SCSI_ERROR) {
1211		metatask->status = CFI_MT_ERROR;
1212		metatask->taskinfo.bbrread.status = CFI_BBR_ERROR;
1213		return;
1214	}
1215
1216	metatask->taskinfo.bbrread.scsi_status = io->scsiio.scsi_status;
1217	memcpy(&metatask->taskinfo.bbrread.sense_data, &io->scsiio.sense_data,
1218	       ctl_min(sizeof(metatask->taskinfo.bbrread.sense_data),
1219		       sizeof(io->scsiio.sense_data)));
1220
1221	if (io->scsiio.scsi_status == SCSI_STATUS_RESERV_CONFLICT) {
1222		metatask->status = CFI_MT_ERROR;
1223		metatask->taskinfo.bbrread.status = CFI_BBR_RESERV_CONFLICT;
1224		return;
1225	}
1226
1227	if (io->scsiio.scsi_status != SCSI_STATUS_CHECK_COND) {
1228		metatask->status = CFI_MT_ERROR;
1229		metatask->taskinfo.bbrread.status = CFI_BBR_SCSI_ERROR;
1230		return;
1231	}
1232
1233	scsi_extract_sense_len(&io->scsiio.sense_data,
1234			       io->scsiio.sense_len,
1235			       &error_code,
1236			       &sense_key,
1237			       &asc,
1238			       &ascq,
1239			       /*show_errors*/ 1);
1240
1241	switch (error_code) {
1242	case SSD_DEFERRED_ERROR:
1243	case SSD_DESC_DEFERRED_ERROR:
1244		metatask->status = CFI_MT_ERROR;
1245		metatask->taskinfo.bbrread.status = CFI_BBR_SCSI_ERROR;
1246		break;
1247	case SSD_CURRENT_ERROR:
1248	case SSD_DESC_CURRENT_ERROR:
1249	default: {
1250		struct scsi_sense_data *sense;
1251
1252		sense = &io->scsiio.sense_data;
1253
1254		if ((asc == 0x04) && (ascq == 0x02)) {
1255			metatask->status = CFI_MT_ERROR;
1256			metatask->taskinfo.bbrread.status = CFI_BBR_LUN_STOPPED;
1257		} else if ((asc == 0x04) && (ascq == 0x03)) {
1258			metatask->status = CFI_MT_ERROR;
1259			metatask->taskinfo.bbrread.status =
1260				CFI_BBR_LUN_OFFLINE_CTL;
1261		} else if ((asc == 0x44) && (ascq == 0x00)) {
1262#ifdef NEEDTOPORT
1263			if (sense->sense_key_spec[0] & SSD_SCS_VALID) {
1264				uint16_t retry_count;
1265
1266				retry_count = sense->sense_key_spec[1] << 8 |
1267					      sense->sense_key_spec[2];
1268				if (((retry_count & 0xf000) == CSC_RAIDCORE)
1269				 && ((retry_count & 0x0f00) == CSC_SHELF_SW)
1270				 && ((retry_count & 0xff) ==
1271				      RC_STS_DEVICE_OFFLINE)) {
1272					metatask->status = CFI_MT_ERROR;
1273					metatask->taskinfo.bbrread.status =
1274						CFI_BBR_LUN_OFFLINE_RC;
1275				} else {
1276					metatask->status = CFI_MT_ERROR;
1277					metatask->taskinfo.bbrread.status =
1278						CFI_BBR_SCSI_ERROR;
1279				}
1280			} else {
1281#endif /* NEEDTOPORT */
1282				metatask->status = CFI_MT_ERROR;
1283				metatask->taskinfo.bbrread.status =
1284					CFI_BBR_SCSI_ERROR;
1285#ifdef NEEDTOPORT
1286			}
1287#endif
1288		} else {
1289			metatask->status = CFI_MT_ERROR;
1290			metatask->taskinfo.bbrread.status = CFI_BBR_SCSI_ERROR;
1291		}
1292		break;
1293	}
1294	}
1295}
1296
1297static void
1298cfi_metatask_io_done(union ctl_io *io)
1299{
1300	struct cfi_lun_io *lun_io;
1301	struct cfi_metatask *metatask;
1302	struct cfi_softc *softc;
1303	struct cfi_lun *lun;
1304
1305	lun_io = (struct cfi_lun_io *)
1306		io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
1307
1308	lun = lun_io->lun;
1309	softc = lun->softc;
1310
1311	metatask = lun_io->metatask;
1312
1313	switch (metatask->tasktype) {
1314	case CFI_TASK_STARTUP:
1315	case CFI_TASK_SHUTDOWN: {
1316		int failed, done, is_start;
1317
1318		failed = 0;
1319		done = 0;
1320		if (metatask->tasktype == CFI_TASK_STARTUP)
1321			is_start = 1;
1322		else
1323			is_start = 0;
1324
1325		mtx_lock(&softc->lock);
1326		if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS)
1327			metatask->taskinfo.startstop.luns_complete++;
1328		else {
1329			metatask->taskinfo.startstop.luns_failed++;
1330			failed = 1;
1331		}
1332		if ((metatask->taskinfo.startstop.luns_complete +
1333		     metatask->taskinfo.startstop.luns_failed) >=
1334		     metatask->taskinfo.startstop.total_luns)
1335			done = 1;
1336
1337		mtx_unlock(&softc->lock);
1338
1339		if (failed != 0) {
1340			printf("%s: LUN %d %s request failed\n", __func__,
1341			       lun_io->lun->lun_id, (is_start == 1) ? "start" :
1342			       "stop");
1343			ctl_io_error_print(io, &lun_io->lun->inq_data);
1344		}
1345		if (done != 0) {
1346			if (metatask->taskinfo.startstop.luns_failed > 0)
1347				metatask->status = CFI_MT_ERROR;
1348			else
1349				metatask->status = CFI_MT_SUCCESS;
1350			cfi_metatask_done(softc, metatask);
1351		}
1352		mtx_lock(&softc->lock);
1353		STAILQ_REMOVE(&lun->io_list, lun_io, cfi_lun_io, links);
1354		mtx_unlock(&softc->lock);
1355
1356		ctl_free_io(io);
1357		break;
1358	}
1359	case CFI_TASK_BBRREAD: {
1360		/*
1361		 * Translate the SCSI error into an enumeration.
1362		 */
1363		cfi_metatask_bbr_errorparse(metatask, io);
1364
1365		mtx_lock(&softc->lock);
1366		STAILQ_REMOVE(&lun->io_list, lun_io, cfi_lun_io, links);
1367		mtx_unlock(&softc->lock);
1368
1369		ctl_free_io(io);
1370
1371		cfi_metatask_done(softc, metatask);
1372		break;
1373	}
1374	default:
1375		/*
1376		 * This shouldn't happen.
1377		 */
1378		mtx_lock(&softc->lock);
1379		STAILQ_REMOVE(&lun->io_list, lun_io, cfi_lun_io, links);
1380		mtx_unlock(&softc->lock);
1381
1382		ctl_free_io(io);
1383		break;
1384	}
1385}
1386
1387static void
1388cfi_err_recovery_done(union ctl_io *io)
1389{
1390	struct cfi_lun_io *lun_io, *orig_lun_io;
1391	struct cfi_lun *lun;
1392	union ctl_io *orig_io;
1393
1394	lun_io = (struct cfi_lun_io *)io->io_hdr.port_priv;
1395	orig_lun_io = lun_io->orig_lun_io;
1396	orig_io = orig_lun_io->ctl_io;
1397	lun = lun_io->lun;
1398
1399	if (io->io_hdr.status != CTL_SUCCESS) {
1400		printf("%s: error recovery action failed.  Original "
1401		       "error:\n", __func__);
1402
1403		ctl_io_error_print(orig_lun_io->ctl_io, &lun->inq_data);
1404
1405		printf("%s: error from error recovery action:\n", __func__);
1406
1407		ctl_io_error_print(io, &lun->inq_data);
1408
1409		printf("%s: trying original command again...\n", __func__);
1410	}
1411
1412	mtx_lock(&lun->softc->lock);
1413	STAILQ_REMOVE(&lun->io_list, lun_io, cfi_lun_io, links);
1414	mtx_unlock(&lun->softc->lock);
1415	ctl_free_io(io);
1416
1417	orig_io->io_hdr.retries--;
1418	orig_io->io_hdr.status = CTL_STATUS_NONE;
1419
1420	if (ctl_queue(orig_io) != CTL_RETVAL_COMPLETE) {
1421		printf("%s: error returned from ctl_queue()!\n", __func__);
1422		STAILQ_REMOVE(&lun->io_list, orig_lun_io,
1423			      cfi_lun_io, links);
1424		ctl_free_io(orig_io);
1425	}
1426}
1427
1428static void
1429cfi_lun_io_done(union ctl_io *io)
1430{
1431	struct cfi_lun *lun;
1432	struct cfi_lun_io *lun_io;
1433
1434	lun_io = (struct cfi_lun_io *)
1435		io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
1436	lun = lun_io->lun;
1437
1438	if (lun_io->metatask == NULL) {
1439		printf("%s: I/O has no metatask pointer, discarding\n",
1440		       __func__);
1441		STAILQ_REMOVE(&lun->io_list, lun_io, cfi_lun_io, links);
1442		ctl_free_io(io);
1443		return;
1444	}
1445	cfi_metatask_io_done(io);
1446}
1447
1448void
1449cfi_action(struct cfi_metatask *metatask)
1450{
1451	struct cfi_softc *softc;
1452
1453	softc = &fetd_internal_softc;
1454
1455	mtx_lock(&softc->lock);
1456
1457	STAILQ_INSERT_TAIL(&softc->metatask_list, metatask, links);
1458
1459	if ((softc->flags & CFI_ONLINE) == 0) {
1460		mtx_unlock(&softc->lock);
1461		metatask->status = CFI_MT_PORT_OFFLINE;
1462		cfi_metatask_done(softc, metatask);
1463		return;
1464	} else
1465		mtx_unlock(&softc->lock);
1466
1467	switch (metatask->tasktype) {
1468	case CFI_TASK_STARTUP:
1469	case CFI_TASK_SHUTDOWN: {
1470		union ctl_io *io;
1471		int da_luns, ios_allocated, do_start;
1472		struct cfi_lun *lun;
1473		STAILQ_HEAD(, ctl_io_hdr) tmp_io_list;
1474
1475		da_luns = 0;
1476		ios_allocated = 0;
1477		STAILQ_INIT(&tmp_io_list);
1478
1479		if (metatask->tasktype == CFI_TASK_STARTUP)
1480			do_start = 1;
1481		else
1482			do_start = 0;
1483
1484		mtx_lock(&softc->lock);
1485		STAILQ_FOREACH(lun, &softc->lun_list, links) {
1486			if (lun->state != CFI_LUN_READY)
1487				continue;
1488
1489			if (SID_TYPE(&lun->inq_data) != T_DIRECT)
1490				continue;
1491			da_luns++;
1492			io = ctl_alloc_io(softc->fe.ctl_pool_ref);
1493			if (io != NULL) {
1494				ios_allocated++;
1495				STAILQ_INSERT_TAIL(&tmp_io_list, &io->io_hdr,
1496						   links);
1497			}
1498		}
1499
1500		if (ios_allocated < da_luns) {
1501			printf("%s: error allocating ctl_io for %s\n",
1502			       __func__, (do_start == 1) ? "startup" :
1503			       "shutdown");
1504			da_luns = ios_allocated;
1505		}
1506
1507		metatask->taskinfo.startstop.total_luns = da_luns;
1508
1509		STAILQ_FOREACH(lun, &softc->lun_list, links) {
1510			struct cfi_lun_io *lun_io;
1511
1512			if (lun->state != CFI_LUN_READY)
1513				continue;
1514
1515			if (SID_TYPE(&lun->inq_data) != T_DIRECT)
1516				continue;
1517
1518			io = (union ctl_io *)STAILQ_FIRST(&tmp_io_list);
1519			if (io == NULL)
1520				break;
1521
1522			STAILQ_REMOVE(&tmp_io_list, &io->io_hdr, ctl_io_hdr,
1523				      links);
1524
1525			ctl_scsi_start_stop(io,
1526					    /*start*/ do_start,
1527					    /*load_eject*/ 0,
1528					    /*immediate*/ 0,
1529					    /*power_conditions*/
1530					    SSS_PC_START_VALID,
1531					    /*onoffline*/ 1,
1532					    /*ctl_tag_type*/ CTL_TAG_ORDERED,
1533					    /*control*/ 0);
1534
1535			cfi_init_io(io,
1536				    /*lun*/ lun,
1537				    /*metatask*/ metatask,
1538				    /*policy*/ CFI_ERR_HARD,
1539				    /*retries*/ 3,
1540				    /*orig_lun_io*/ NULL,
1541				    /*done_function*/ cfi_lun_io_done);
1542
1543			lun_io = (struct cfi_lun_io *) io->io_hdr.port_priv;
1544
1545			STAILQ_INSERT_TAIL(&lun->io_list, lun_io, links);
1546
1547			if (ctl_queue(io) != CTL_RETVAL_COMPLETE) {
1548				printf("%s: error returned from ctl_queue()!\n",
1549				       __func__);
1550				STAILQ_REMOVE(&lun->io_list, lun_io,
1551					      cfi_lun_io, links);
1552				ctl_free_io(io);
1553				metatask->taskinfo.startstop.total_luns--;
1554			}
1555		}
1556
1557		if (STAILQ_FIRST(&tmp_io_list) != NULL) {
1558			printf("%s: error: tmp_io_list != NULL\n", __func__);
1559			for (io = (union ctl_io *)STAILQ_FIRST(&tmp_io_list);
1560			     io != NULL;
1561			     io = (union ctl_io *)STAILQ_FIRST(&tmp_io_list)) {
1562				STAILQ_REMOVE(&tmp_io_list, &io->io_hdr,
1563					      ctl_io_hdr, links);
1564				ctl_free_io(io);
1565			}
1566		}
1567		mtx_unlock(&softc->lock);
1568
1569		break;
1570	}
1571	case CFI_TASK_BBRREAD: {
1572		union ctl_io *io;
1573		struct cfi_lun *lun;
1574		struct cfi_lun_io *lun_io;
1575		cfi_bbrread_status status;
1576		int req_lun_num;
1577		uint32_t num_blocks;
1578
1579		status = CFI_BBR_SUCCESS;
1580
1581		req_lun_num = metatask->taskinfo.bbrread.lun_num;
1582
1583		mtx_lock(&softc->lock);
1584		STAILQ_FOREACH(lun, &softc->lun_list, links) {
1585			if (lun->lun_id != req_lun_num)
1586				continue;
1587			if (lun->state != CFI_LUN_READY) {
1588				status = CFI_BBR_LUN_UNCONFIG;
1589				break;
1590			} else
1591				break;
1592		}
1593
1594		if (lun == NULL)
1595			status = CFI_BBR_NO_LUN;
1596
1597		if (status != CFI_BBR_SUCCESS) {
1598			metatask->status = CFI_MT_ERROR;
1599			metatask->taskinfo.bbrread.status = status;
1600			mtx_unlock(&softc->lock);
1601			cfi_metatask_done(softc, metatask);
1602			break;
1603		}
1604
1605		/*
1606		 * Convert the number of bytes given into blocks and check
1607		 * that the number of bytes is a multiple of the blocksize.
1608		 * CTL will verify that the LBA is okay.
1609		 */
1610		if (lun->blocksize_powerof2 != 0) {
1611			if ((metatask->taskinfo.bbrread.len &
1612			    (lun->blocksize - 1)) != 0) {
1613				metatask->status = CFI_MT_ERROR;
1614				metatask->taskinfo.bbrread.status =
1615					CFI_BBR_BAD_LEN;
1616				cfi_metatask_done(softc, metatask);
1617				break;
1618			}
1619
1620			num_blocks = metatask->taskinfo.bbrread.len >>
1621				lun->blocksize_powerof2;
1622		} else {
1623			/*
1624			 * XXX KDM this could result in floating point
1625			 * division, which isn't supported in the kernel on
1626			 * x86 at least.
1627			 */
1628			if ((metatask->taskinfo.bbrread.len %
1629			     lun->blocksize) != 0) {
1630				metatask->status = CFI_MT_ERROR;
1631				metatask->taskinfo.bbrread.status =
1632					CFI_BBR_BAD_LEN;
1633				cfi_metatask_done(softc, metatask);
1634				break;
1635			}
1636
1637			/*
1638			 * XXX KDM this could result in floating point
1639			 * division in some cases.
1640			 */
1641			num_blocks = metatask->taskinfo.bbrread.len /
1642				lun->blocksize;
1643
1644		}
1645
1646		io = ctl_alloc_io(softc->fe.ctl_pool_ref);
1647		if (io == NULL) {
1648			metatask->status = CFI_MT_ERROR;
1649			metatask->taskinfo.bbrread.status = CFI_BBR_NO_MEM;
1650			mtx_unlock(&softc->lock);
1651			cfi_metatask_done(softc, metatask);
1652			break;
1653		}
1654
1655		/*
1656		 * XXX KDM need to do a read capacity to get the blocksize
1657		 * for this device.
1658		 */
1659		ctl_scsi_read_write(io,
1660				    /*data_ptr*/ NULL,
1661				    /*data_len*/ metatask->taskinfo.bbrread.len,
1662				    /*read_op*/ 1,
1663				    /*byte2*/ 0,
1664				    /*minimum_cdb_size*/ 0,
1665				    /*lba*/ metatask->taskinfo.bbrread.lba,
1666				    /*num_blocks*/ num_blocks,
1667				    /*tag_type*/ CTL_TAG_SIMPLE,
1668				    /*control*/ 0);
1669
1670		cfi_init_io(io,
1671			    /*lun*/ lun,
1672			    /*metatask*/ metatask,
1673			    /*policy*/ CFI_ERR_SOFT,
1674			    /*retries*/ 3,
1675			    /*orig_lun_io*/ NULL,
1676			    /*done_function*/ cfi_lun_io_done);
1677
1678		lun_io = (struct cfi_lun_io *)io->io_hdr.port_priv;
1679
1680		STAILQ_INSERT_TAIL(&lun->io_list, lun_io, links);
1681
1682		if (ctl_queue(io) != CTL_RETVAL_COMPLETE) {
1683			printf("%s: error returned from ctl_queue()!\n",
1684			       __func__);
1685			STAILQ_REMOVE(&lun->io_list, lun_io, cfi_lun_io, links);
1686			ctl_free_io(io);
1687			metatask->status = CFI_MT_ERROR;
1688			metatask->taskinfo.bbrread.status = CFI_BBR_ERROR;
1689			mtx_unlock(&softc->lock);
1690			cfi_metatask_done(softc, metatask);
1691			break;
1692		}
1693
1694		mtx_unlock(&softc->lock);
1695		break;
1696	}
1697	default:
1698		panic("invalid metatask type %d", metatask->tasktype);
1699		break; /* NOTREACHED */
1700	}
1701}
1702
1703#ifdef oldapi
1704void
1705cfi_shutdown_shelf(cfi_cb_t callback, void *callback_arg)
1706{
1707	struct ctl_mem_element *element;
1708	struct cfi_softc *softc;
1709	struct cfi_metatask *metatask;
1710
1711	softc = &fetd_internal_softc;
1712
1713	element = ctl_alloc_mem_element(&softc->metatask_pool, /*can_wait*/ 0);
1714	if (element == NULL) {
1715		callback(callback_arg,
1716			 /*status*/ CFI_MT_ERROR,
1717			 /*sluns_found*/ 0,
1718			 /*sluns_complete*/ 0,
1719			 /*sluns_failed*/ 0);
1720		return;
1721	}
1722
1723	metatask = (struct cfi_metatask *)element->bytes;
1724
1725	memset(metatask, 0, sizeof(*metatask));
1726	metatask->tasktype = CFI_TASK_SHUTDOWN;
1727	metatask->status = CFI_MT_NONE;
1728	metatask->taskinfo.startstop.callback = callback;
1729	metatask->taskinfo.startstop.callback_arg = callback_arg;
1730	metatask->element = element;
1731
1732	cfi_action(softc, metatask);
1733
1734	/*
1735	 * - send a report luns to lun 0, get LUN list.
1736	 * - send an inquiry to each lun
1737	 * - send a stop/offline to each direct access LUN
1738	 *    - if we get a reservation conflict, reset the LUN and then
1739	 *      retry sending the stop/offline
1740	 * - return status back to the caller
1741	 */
1742}
1743
1744void
1745cfi_start_shelf(cfi_cb_t callback, void *callback_arg)
1746{
1747	struct ctl_mem_element *element;
1748	struct cfi_softc *softc;
1749	struct cfi_metatask *metatask;
1750
1751	softc = &fetd_internal_softc;
1752
1753	element = ctl_alloc_mem_element(&softc->metatask_pool, /*can_wait*/ 0);
1754	if (element == NULL) {
1755		callback(callback_arg,
1756			 /*status*/ CFI_MT_ERROR,
1757			 /*sluns_found*/ 0,
1758			 /*sluns_complete*/ 0,
1759			 /*sluns_failed*/ 0);
1760		return;
1761	}
1762
1763	metatask = (struct cfi_metatask *)element->bytes;
1764
1765	memset(metatask, 0, sizeof(*metatask));
1766	metatask->tasktype = CFI_TASK_STARTUP;
1767	metatask->status = CFI_MT_NONE;
1768	metatask->taskinfo.startstop.callback = callback;
1769	metatask->taskinfo.startstop.callback_arg = callback_arg;
1770	metatask->element = element;
1771
1772	cfi_action(softc, metatask);
1773
1774	/*
1775	 * - send a report luns to lun 0, get LUN list.
1776	 * - send an inquiry to each lun
1777	 * - send a stop/offline to each direct access LUN
1778	 *    - if we get a reservation conflict, reset the LUN and then
1779	 *      retry sending the stop/offline
1780	 * - return status back to the caller
1781	 */
1782}
1783
1784#endif
1785
1786struct cfi_metatask *
1787cfi_alloc_metatask(int can_wait)
1788{
1789	struct ctl_mem_element *element;
1790	struct cfi_metatask *metatask;
1791	struct cfi_softc *softc;
1792
1793	softc = &fetd_internal_softc;
1794
1795	element = ctl_alloc_mem_element(&softc->metatask_pool, can_wait);
1796	if (element == NULL)
1797		return (NULL);
1798
1799	metatask = (struct cfi_metatask *)element->bytes;
1800	memset(metatask, 0, sizeof(*metatask));
1801	metatask->status = CFI_MT_NONE;
1802	metatask->element = element;
1803
1804	return (metatask);
1805}
1806
1807void
1808cfi_free_metatask(struct cfi_metatask *metatask)
1809{
1810	ctl_free_mem_element(metatask->element);
1811}
1812
1813/*
1814 * vim: ts=8
1815 */
1816