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