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