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