Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / sys / bus / cam / cam_periph.c
1 /*
2  * Common functions for CAM "type" (peripheral) drivers.
3  *
4  * Copyright (c) 1997, 1998 Justin T. Gibbs.
5  * Copyright (c) 1997, 1998, 1999, 2000 Kenneth D. Merry.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions, and the following disclaimer,
13  *    without modification, immediately at the beginning of the file.
14  * 2. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD: src/sys/cam/cam_periph.c,v 1.24.2.3 2003/01/25 19:04:40 dillon Exp $
30  * $DragonFly: src/sys/bus/cam/cam_periph.c,v 1.2 2003/06/17 04:28:18 dillon Exp $
31  */
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/types.h>
36 #include <sys/malloc.h>
37 #include <sys/linker_set.h>
38 #include <sys/buf.h>
39 #include <sys/proc.h>
40 #include <sys/devicestat.h>
41 #include <sys/bus.h>
42 #include <vm/vm.h>
43 #include <vm/vm_extern.h>
44
45 #include <cam/cam.h>
46 #include <cam/cam_ccb.h>
47 #include <cam/cam_xpt_periph.h>
48 #include <cam/cam_periph.h>
49 #include <cam/cam_debug.h>
50
51 #include <cam/scsi/scsi_all.h>
52 #include <cam/scsi/scsi_message.h>
53 #include <cam/scsi/scsi_da.h>
54 #include <cam/scsi/scsi_pass.h>
55
56 static  u_int           camperiphnextunit(struct periph_driver *p_drv,
57                                           u_int newunit, int wired,
58                                           path_id_t pathid, target_id_t target,
59                                           lun_id_t lun);
60 static  u_int           camperiphunit(struct periph_driver *p_drv,
61                                       path_id_t pathid, target_id_t target,
62                                       lun_id_t lun); 
63 static  void            camperiphdone(struct cam_periph *periph, 
64                                         union ccb *done_ccb);
65 static  void            camperiphfree(struct cam_periph *periph);
66
67 cam_status
68 cam_periph_alloc(periph_ctor_t *periph_ctor,
69                  periph_oninv_t *periph_oninvalidate,
70                  periph_dtor_t *periph_dtor, periph_start_t *periph_start,
71                  char *name, cam_periph_type type, struct cam_path *path,
72                  ac_callback_t *ac_callback, ac_code code, void *arg)
73 {
74         struct          periph_driver **p_drv;
75         struct          cam_periph *periph;
76         struct          cam_periph *cur_periph;
77         path_id_t       path_id;
78         target_id_t     target_id;
79         lun_id_t        lun_id;
80         cam_status      status;
81         u_int           init_level;
82         int s;
83
84         init_level = 0;
85         /*
86          * Handle Hot-Plug scenarios.  If there is already a peripheral
87          * of our type assigned to this path, we are likely waiting for
88          * final close on an old, invalidated, peripheral.  If this is
89          * the case, queue up a deferred call to the peripheral's async
90          * handler.  If it looks like a mistaken re-alloation, complain.
91          */
92         if ((periph = cam_periph_find(path, name)) != NULL) {
93
94                 if ((periph->flags & CAM_PERIPH_INVALID) != 0
95                  && (periph->flags & CAM_PERIPH_NEW_DEV_FOUND) == 0) {
96                         periph->flags |= CAM_PERIPH_NEW_DEV_FOUND;
97                         periph->deferred_callback = ac_callback;
98                         periph->deferred_ac = code;
99                         return (CAM_REQ_INPROG);
100                 } else {
101                         printf("cam_periph_alloc: attempt to re-allocate "
102                                "valid device %s%d rejected\n",
103                                periph->periph_name, periph->unit_number);
104                 }
105                 return (CAM_REQ_INVALID);
106         }
107         
108         periph = (struct cam_periph *)malloc(sizeof(*periph), M_DEVBUF,
109                                              M_NOWAIT);
110
111         if (periph == NULL)
112                 return (CAM_RESRC_UNAVAIL);
113         
114         init_level++;
115
116         for (p_drv = (struct periph_driver **)periphdriver_set.ls_items;
117              *p_drv != NULL; p_drv++) {
118                 if (strcmp((*p_drv)->driver_name, name) == 0)
119                         break;
120         }
121         
122         path_id = xpt_path_path_id(path);
123         target_id = xpt_path_target_id(path);
124         lun_id = xpt_path_lun_id(path);
125         bzero(periph, sizeof(*periph));
126         cam_init_pinfo(&periph->pinfo);
127         periph->periph_start = periph_start;
128         periph->periph_dtor = periph_dtor;
129         periph->periph_oninval = periph_oninvalidate;
130         periph->type = type;
131         periph->periph_name = name;
132         periph->unit_number = camperiphunit(*p_drv, path_id, target_id, lun_id);
133         periph->immediate_priority = CAM_PRIORITY_NONE;
134         periph->refcount = 0;
135         SLIST_INIT(&periph->ccb_list);
136         status = xpt_create_path(&path, periph, path_id, target_id, lun_id);
137         if (status != CAM_REQ_CMP)
138                 goto failure;
139
140         periph->path = path;
141         init_level++;
142
143         status = xpt_add_periph(periph);
144
145         if (status != CAM_REQ_CMP)
146                 goto failure;
147
148         s = splsoftcam();
149         cur_periph = TAILQ_FIRST(&(*p_drv)->units);
150         while (cur_periph != NULL
151             && cur_periph->unit_number < periph->unit_number)
152                 cur_periph = TAILQ_NEXT(cur_periph, unit_links);
153
154         if (cur_periph != NULL)
155                 TAILQ_INSERT_BEFORE(cur_periph, periph, unit_links);
156         else {
157                 TAILQ_INSERT_TAIL(&(*p_drv)->units, periph, unit_links);
158                 (*p_drv)->generation++;
159         }
160
161         splx(s);
162
163         init_level++;
164
165         status = periph_ctor(periph, arg);
166
167         if (status == CAM_REQ_CMP)
168                 init_level++;
169
170 failure:
171         switch (init_level) {
172         case 4:
173                 /* Initialized successfully */
174                 break;
175         case 3:
176                 s = splsoftcam();
177                 TAILQ_REMOVE(&(*p_drv)->units, periph, unit_links);
178                 splx(s);
179                 xpt_remove_periph(periph);
180         case 2:
181                 xpt_free_path(periph->path);
182         case 1:
183                 free(periph, M_DEVBUF);
184         case 0:
185                 /* No cleanup to perform. */
186                 break;
187         default:
188                 panic("cam_periph_alloc: Unkown init level");
189         }
190         return(status);
191 }
192
193 /*
194  * Find a peripheral structure with the specified path, target, lun, 
195  * and (optionally) type.  If the name is NULL, this function will return
196  * the first peripheral driver that matches the specified path.
197  */
198 struct cam_periph *
199 cam_periph_find(struct cam_path *path, char *name)
200 {
201         struct periph_driver **p_drv;
202         struct cam_periph *periph;
203         int s;
204
205         for (p_drv = (struct periph_driver **)periphdriver_set.ls_items;
206              *p_drv != NULL; p_drv++) {
207
208                 if (name != NULL && (strcmp((*p_drv)->driver_name, name) != 0))
209                         continue;
210
211                 s = splsoftcam();
212                 for (periph = TAILQ_FIRST(&(*p_drv)->units); periph != NULL;
213                      periph = TAILQ_NEXT(periph, unit_links)) {
214                         if (xpt_path_comp(periph->path, path) == 0) {
215                                 splx(s);
216                                 return(periph);
217                         }
218                 }
219                 splx(s);
220                 if (name != NULL)
221                         return(NULL);
222         }
223         return(NULL);
224 }
225
226 cam_status
227 cam_periph_acquire(struct cam_periph *periph)
228 {
229         int s;
230
231         if (periph == NULL)
232                 return(CAM_REQ_CMP_ERR);
233
234         s = splsoftcam();
235         periph->refcount++;
236         splx(s);
237
238         return(CAM_REQ_CMP);
239 }
240
241 void
242 cam_periph_release(struct cam_periph *periph)
243 {
244         int s;
245
246         if (periph == NULL)
247                 return;
248
249         s = splsoftcam();
250         if ((--periph->refcount == 0)
251          && (periph->flags & CAM_PERIPH_INVALID)) {
252                 camperiphfree(periph);
253         }
254         splx(s);
255
256 }
257
258 /*
259  * Look for the next unit number that is not currently in use for this
260  * peripheral type starting at "newunit".  Also exclude unit numbers that
261  * are reserved by for future "hardwiring" unless we already know that this
262  * is a potential wired device.  Only assume that the device is "wired" the
263  * first time through the loop since after that we'll be looking at unit
264  * numbers that did not match a wiring entry.
265  */
266 static u_int
267 camperiphnextunit(struct periph_driver *p_drv, u_int newunit, int wired,
268                   path_id_t pathid, target_id_t target, lun_id_t lun)
269 {
270         struct  cam_periph *periph;
271         char    *periph_name, *strval;
272         int     s;
273         int     i, val, dunit;
274         const char *dname;
275
276         s = splsoftcam();
277         periph_name = p_drv->driver_name;
278         for (;;newunit++) {
279
280                 for (periph = TAILQ_FIRST(&p_drv->units);
281                      periph != NULL && periph->unit_number != newunit;
282                      periph = TAILQ_NEXT(periph, unit_links))
283                         ;
284
285                 if (periph != NULL && periph->unit_number == newunit) {
286                         if (wired != 0) {
287                                 xpt_print_path(periph->path);
288                                 printf("Duplicate Wired Device entry!\n");
289                                 xpt_print_path(periph->path);
290                                 printf("Second device (%s device at scbus%d "
291                                        "target %d lun %d) will not be wired\n",
292                                        periph_name, pathid, target, lun);
293                                 wired = 0;
294                         }
295                         continue;
296                 }
297                 if (wired)
298                         break;
299
300                 /*
301                  * Don't match entries like "da 4" as a wired down
302                  * device, but do match entries like "da 4 target 5"
303                  * or even "da 4 scbus 1". 
304                  */
305                 i = -1;
306                 while ((i = resource_locate(i, periph_name)) != -1) {
307                         dname = resource_query_name(i);
308                         dunit = resource_query_unit(i);
309                         /* if no "target" and no specific scbus, skip */
310                         if (resource_int_value(dname, dunit, "target", &val) &&
311                             (resource_string_value(dname, dunit, "at",&strval)||
312                              strcmp(strval, "scbus") == 0))
313                                 continue;
314                         if (newunit == dunit)
315                                 break;
316                 }
317                 if (i == -1)
318                         break;
319         }
320         splx(s);
321         return (newunit);
322 }
323
324 static u_int
325 camperiphunit(struct periph_driver *p_drv, path_id_t pathid,
326               target_id_t target, lun_id_t lun)
327 {
328         u_int   unit;
329         int     hit, i, val, dunit;
330         const char *dname;
331         char    pathbuf[32], *strval, *periph_name;
332
333         unit = 0;
334
335         periph_name = p_drv->driver_name;
336         snprintf(pathbuf, sizeof(pathbuf), "scbus%d", pathid);
337         i = -1;
338         for (hit = 0; (i = resource_locate(i, periph_name)) != -1; hit = 0) {
339                 dname = resource_query_name(i);
340                 dunit = resource_query_unit(i);
341                 if (resource_string_value(dname, dunit, "at", &strval) == 0) {
342                         if (strcmp(strval, pathbuf) != 0)
343                                 continue;
344                         hit++;
345                 }
346                 if (resource_int_value(dname, dunit, "target", &val) == 0) {
347                         if (val != target)
348                                 continue;
349                         hit++;
350                 }
351                 if (resource_int_value(dname, dunit, "lun", &val) == 0) {
352                         if (val != lun)
353                                 continue;
354                         hit++;
355                 }
356                 if (hit != 0) {
357                         unit = dunit;
358                         break;
359                 }
360         }
361
362         /*
363          * Either start from 0 looking for the next unit or from
364          * the unit number given in the resource config.  This way,
365          * if we have wildcard matches, we don't return the same
366          * unit number twice.
367          */
368         unit = camperiphnextunit(p_drv, unit, /*wired*/hit, pathid,
369                                  target, lun);
370
371         return (unit);
372 }
373
374 void
375 cam_periph_invalidate(struct cam_periph *periph)
376 {
377         int s;
378
379         s = splsoftcam();
380         /*
381          * We only call this routine the first time a peripheral is
382          * invalidated.  The oninvalidate() routine is always called at
383          * splsoftcam().
384          */
385         if (((periph->flags & CAM_PERIPH_INVALID) == 0)
386          && (periph->periph_oninval != NULL))
387                 periph->periph_oninval(periph);
388
389         periph->flags |= CAM_PERIPH_INVALID;
390         periph->flags &= ~CAM_PERIPH_NEW_DEV_FOUND;
391
392         if (periph->refcount == 0)
393                 camperiphfree(periph);
394         else if (periph->refcount < 0)
395                 printf("cam_invalidate_periph: refcount < 0!!\n");
396         splx(s);
397 }
398
399 static void
400 camperiphfree(struct cam_periph *periph)
401 {
402         int s;
403         struct periph_driver **p_drv;
404
405         for (p_drv = (struct periph_driver **)periphdriver_set.ls_items;
406              *p_drv != NULL; p_drv++) {
407                 if (strcmp((*p_drv)->driver_name, periph->periph_name) == 0)
408                         break;
409         }
410         
411         if (periph->periph_dtor != NULL)
412                 periph->periph_dtor(periph);
413         
414         s = splsoftcam();
415         TAILQ_REMOVE(&(*p_drv)->units, periph, unit_links);
416         (*p_drv)->generation++;
417         splx(s);
418
419         xpt_remove_periph(periph);
420
421         if (periph->flags & CAM_PERIPH_NEW_DEV_FOUND) {
422                 union ccb ccb;
423                 void *arg;
424
425                 switch (periph->deferred_ac) {
426                 case AC_FOUND_DEVICE:
427                         ccb.ccb_h.func_code = XPT_GDEV_TYPE;
428                         xpt_setup_ccb(&ccb.ccb_h, periph->path, /*priority*/ 1);
429                         xpt_action(&ccb);
430                         arg = &ccb;
431                         break;
432                 case AC_PATH_REGISTERED:
433                         ccb.ccb_h.func_code = XPT_PATH_INQ;
434                         xpt_setup_ccb(&ccb.ccb_h, periph->path, /*priority*/ 1);
435                         xpt_action(&ccb);
436                         arg = &ccb;
437                         break;
438                 default:
439                         arg = NULL;
440                         break;
441                 }
442                 periph->deferred_callback(NULL, periph->deferred_ac,
443                                           periph->path, arg);
444         }
445         xpt_free_path(periph->path);
446         free(periph, M_DEVBUF);
447 }
448
449 /*
450  * Wait interruptibly for an exclusive lock.
451  */
452 int
453 cam_periph_lock(struct cam_periph *periph, int priority)
454 {
455         int error;
456
457         while ((periph->flags & CAM_PERIPH_LOCKED) != 0) {
458                 periph->flags |= CAM_PERIPH_LOCK_WANTED;
459                 if ((error = tsleep(periph, priority, "caplck", 0)) != 0)
460                         return error;
461         }
462
463         if (cam_periph_acquire(periph) != CAM_REQ_CMP)
464                 return(ENXIO);
465
466         periph->flags |= CAM_PERIPH_LOCKED;
467         return 0;
468 }
469
470 /*
471  * Unlock and wake up any waiters.
472  */
473 void
474 cam_periph_unlock(struct cam_periph *periph)
475 {
476         periph->flags &= ~CAM_PERIPH_LOCKED;
477         if ((periph->flags & CAM_PERIPH_LOCK_WANTED) != 0) {
478                 periph->flags &= ~CAM_PERIPH_LOCK_WANTED;
479                 wakeup(periph);
480         }
481
482         cam_periph_release(periph);
483 }
484
485 /*
486  * Map user virtual pointers into kernel virtual address space, so we can
487  * access the memory.  This won't work on physical pointers, for now it's
488  * up to the caller to check for that.  (XXX KDM -- should we do that here
489  * instead?)  This also only works for up to MAXPHYS memory.  Since we use
490  * buffers to map stuff in and out, we're limited to the buffer size.
491  */
492 int
493 cam_periph_mapmem(union ccb *ccb, struct cam_periph_map_info *mapinfo)
494 {
495         int numbufs, i, j;
496         int flags[CAM_PERIPH_MAXMAPS];
497         u_int8_t **data_ptrs[CAM_PERIPH_MAXMAPS];
498         u_int32_t lengths[CAM_PERIPH_MAXMAPS];
499         u_int32_t dirs[CAM_PERIPH_MAXMAPS];
500
501         switch(ccb->ccb_h.func_code) {
502         case XPT_DEV_MATCH:
503                 if (ccb->cdm.match_buf_len == 0) {
504                         printf("cam_periph_mapmem: invalid match buffer "
505                                "length 0\n");
506                         return(EINVAL);
507                 }
508                 if (ccb->cdm.pattern_buf_len > 0) {
509                         data_ptrs[0] = (u_int8_t **)&ccb->cdm.patterns;
510                         lengths[0] = ccb->cdm.pattern_buf_len;
511                         dirs[0] = CAM_DIR_OUT;
512                         data_ptrs[1] = (u_int8_t **)&ccb->cdm.matches;
513                         lengths[1] = ccb->cdm.match_buf_len;
514                         dirs[1] = CAM_DIR_IN;
515                         numbufs = 2;
516                 } else {
517                         data_ptrs[0] = (u_int8_t **)&ccb->cdm.matches;
518                         lengths[0] = ccb->cdm.match_buf_len;
519                         dirs[0] = CAM_DIR_IN;
520                         numbufs = 1;
521                 }
522                 break;
523         case XPT_SCSI_IO:
524         case XPT_CONT_TARGET_IO:
525                 if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE)
526                         return(0);
527
528                 data_ptrs[0] = &ccb->csio.data_ptr;
529                 lengths[0] = ccb->csio.dxfer_len;
530                 dirs[0] = ccb->ccb_h.flags & CAM_DIR_MASK;
531                 numbufs = 1;
532                 break;
533         default:
534                 return(EINVAL);
535                 break; /* NOTREACHED */
536         }
537
538         /*
539          * Check the transfer length and permissions first, so we don't
540          * have to unmap any previously mapped buffers.
541          */
542         for (i = 0; i < numbufs; i++) {
543
544                 flags[i] = 0;
545
546                 /*
547                  * The userland data pointer passed in may not be page
548                  * aligned.  vmapbuf() truncates the address to a page
549                  * boundary, so if the address isn't page aligned, we'll
550                  * need enough space for the given transfer length, plus
551                  * whatever extra space is necessary to make it to the page
552                  * boundary.
553                  */
554                 if ((lengths[i] +
555                     (((vm_offset_t)(*data_ptrs[i])) & PAGE_MASK)) > DFLTPHYS){
556                         printf("cam_periph_mapmem: attempt to map %lu bytes, "
557                                "which is greater than DFLTPHYS(%d)\n",
558                                (long)(lengths[i] +
559                                (((vm_offset_t)(*data_ptrs[i])) & PAGE_MASK)),
560                                DFLTPHYS);
561                         return(E2BIG);
562                 }
563
564                 if (dirs[i] & CAM_DIR_OUT) {
565                         flags[i] = B_WRITE;
566                         if (!useracc(*data_ptrs[i], lengths[i], 
567                                      VM_PROT_READ)) {
568                                 printf("cam_periph_mapmem: error, "
569                                         "address %p, length %lu isn't "
570                                         "user accessible for READ\n",
571                                         (void *)*data_ptrs[i],
572                                         (u_long)lengths[i]);
573                                 return(EACCES);
574                         }
575                 }
576
577                 /*
578                  * XXX this check is really bogus, since B_WRITE currently
579                  * is all 0's, and so it is "set" all the time.
580                  */
581                 if (dirs[i] & CAM_DIR_IN) {
582                         flags[i] |= B_READ;
583                         if (!useracc(*data_ptrs[i], lengths[i], 
584                                      VM_PROT_WRITE)) {
585                                 printf("cam_periph_mapmem: error, "
586                                         "address %p, length %lu isn't "
587                                         "user accessible for WRITE\n",
588                                         (void *)*data_ptrs[i],
589                                         (u_long)lengths[i]);
590
591                                 return(EACCES);
592                         }
593                 }
594
595         }
596
597         /* this keeps the current process from getting swapped */
598         /*
599          * XXX KDM should I use P_NOSWAP instead?
600          */
601         PHOLD(curproc);
602
603         for (i = 0; i < numbufs; i++) {
604                 /*
605                  * Get the buffer.
606                  */
607                 mapinfo->bp[i] = getpbuf(NULL);
608
609                 /* save the buffer's data address */
610                 mapinfo->bp[i]->b_saveaddr = mapinfo->bp[i]->b_data;
611
612                 /* put our pointer in the data slot */
613                 mapinfo->bp[i]->b_data = *data_ptrs[i];
614
615                 /* set the transfer length, we know it's < DFLTPHYS */
616                 mapinfo->bp[i]->b_bufsize = lengths[i];
617
618                 /* set the flags */
619                 mapinfo->bp[i]->b_flags = flags[i] | B_PHYS;
620
621                 /* map the buffer into kernel memory */
622                 if (vmapbuf(mapinfo->bp[i]) < 0) {
623                         printf("cam_periph_mapmem: error, "
624                                 "address %p, length %lu isn't "
625                                 "user accessible any more\n",
626                                 (void *)*data_ptrs[i],
627                                 (u_long)lengths[i]);
628                         for (j = 0; j < i; ++j) {
629                                 *data_ptrs[j] = mapinfo->bp[j]->b_saveaddr;
630                                 mapinfo->bp[j]->b_flags &= ~B_PHYS;
631                                 relpbuf(mapinfo->bp[j], NULL);
632                         }
633                         PRELE(curproc);
634                         return(EACCES);
635                 }
636
637                 /* set our pointer to the new mapped area */
638                 *data_ptrs[i] = mapinfo->bp[i]->b_data;
639
640                 mapinfo->num_bufs_used++;
641         }
642
643         return(0);
644 }
645
646 /*
647  * Unmap memory segments mapped into kernel virtual address space by
648  * cam_periph_mapmem().
649  */
650 void
651 cam_periph_unmapmem(union ccb *ccb, struct cam_periph_map_info *mapinfo)
652 {
653         int numbufs, i;
654         u_int8_t **data_ptrs[CAM_PERIPH_MAXMAPS];
655
656         if (mapinfo->num_bufs_used <= 0) {
657                 /* allow ourselves to be swapped once again */
658                 PRELE(curproc);
659                 return;
660         }
661
662         switch (ccb->ccb_h.func_code) {
663         case XPT_DEV_MATCH:
664                 numbufs = min(mapinfo->num_bufs_used, 2);
665
666                 if (numbufs == 1) {
667                         data_ptrs[0] = (u_int8_t **)&ccb->cdm.matches;
668                 } else {
669                         data_ptrs[0] = (u_int8_t **)&ccb->cdm.patterns;
670                         data_ptrs[1] = (u_int8_t **)&ccb->cdm.matches;
671                 }
672                 break;
673         case XPT_SCSI_IO:
674         case XPT_CONT_TARGET_IO:
675                 data_ptrs[0] = &ccb->csio.data_ptr;
676                 numbufs = min(mapinfo->num_bufs_used, 1);
677                 break;
678         default:
679                 /* allow ourselves to be swapped once again */
680                 PRELE(curproc);
681                 return;
682                 break; /* NOTREACHED */ 
683         }
684
685         for (i = 0; i < numbufs; i++) {
686                 /* Set the user's pointer back to the original value */
687                 *data_ptrs[i] = mapinfo->bp[i]->b_saveaddr;
688
689                 /* unmap the buffer */
690                 vunmapbuf(mapinfo->bp[i]);
691
692                 /* clear the flags we set above */
693                 mapinfo->bp[i]->b_flags &= ~B_PHYS;
694
695                 /* release the buffer */
696                 relpbuf(mapinfo->bp[i], NULL);
697         }
698
699         /* allow ourselves to be swapped once again */
700         PRELE(curproc);
701 }
702
703 union ccb *
704 cam_periph_getccb(struct cam_periph *periph, u_int32_t priority)
705 {
706         struct ccb_hdr *ccb_h;
707         int s;
708
709         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdgetccb\n"));
710
711         s = splsoftcam();
712         
713         while (periph->ccb_list.slh_first == NULL) {
714                 if (periph->immediate_priority > priority)
715                         periph->immediate_priority = priority;
716                 xpt_schedule(periph, priority);
717                 if ((periph->ccb_list.slh_first != NULL)
718                  && (periph->ccb_list.slh_first->pinfo.priority == priority))
719                         break;
720                 tsleep(&periph->ccb_list, PRIBIO, "cgticb", 0);
721         }
722
723         ccb_h = periph->ccb_list.slh_first;
724         SLIST_REMOVE_HEAD(&periph->ccb_list, periph_links.sle);
725         splx(s);
726         return ((union ccb *)ccb_h);
727 }
728
729 void
730 cam_periph_ccbwait(union ccb *ccb)
731 {
732         int s;
733
734         s = splsoftcam();
735         if ((ccb->ccb_h.pinfo.index != CAM_UNQUEUED_INDEX)
736          || ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG))
737                 tsleep(&ccb->ccb_h.cbfcnp, PRIBIO, "cbwait", 0);
738
739         splx(s);
740 }
741
742 int
743 cam_periph_ioctl(struct cam_periph *periph, int cmd, caddr_t addr,
744                  int (*error_routine)(union ccb *ccb, 
745                                       cam_flags camflags,
746                                       u_int32_t sense_flags))
747 {
748         union ccb            *ccb;
749         int                  error;
750         int                  found;
751
752         error = found = 0;
753
754         switch(cmd){
755         case CAMGETPASSTHRU:
756                 ccb = cam_periph_getccb(periph, /* priority */ 1);
757                 xpt_setup_ccb(&ccb->ccb_h,
758                               ccb->ccb_h.path,
759                               /*priority*/1);
760                 ccb->ccb_h.func_code = XPT_GDEVLIST;
761
762                 /*
763                  * Basically, the point of this is that we go through
764                  * getting the list of devices, until we find a passthrough
765                  * device.  In the current version of the CAM code, the
766                  * only way to determine what type of device we're dealing
767                  * with is by its name.
768                  */
769                 while (found == 0) {
770                         ccb->cgdl.index = 0;
771                         ccb->cgdl.status = CAM_GDEVLIST_MORE_DEVS;
772                         while (ccb->cgdl.status == CAM_GDEVLIST_MORE_DEVS) {
773
774                                 /* we want the next device in the list */
775                                 xpt_action(ccb);
776                                 if (strncmp(ccb->cgdl.periph_name, 
777                                     "pass", 4) == 0){
778                                         found = 1;
779                                         break;
780                                 }
781                         }
782                         if ((ccb->cgdl.status == CAM_GDEVLIST_LAST_DEVICE) &&
783                             (found == 0)) {
784                                 ccb->cgdl.periph_name[0] = '\0';
785                                 ccb->cgdl.unit_number = 0;
786                                 break;
787                         }
788                 }
789
790                 /* copy the result back out */  
791                 bcopy(ccb, addr, sizeof(union ccb));
792
793                 /* and release the ccb */
794                 xpt_release_ccb(ccb);
795
796                 break;
797         default:
798                 error = ENOTTY;
799                 break;
800         }
801         return(error);
802 }
803
804 int
805 cam_periph_runccb(union ccb *ccb,
806                   int (*error_routine)(union ccb *ccb,
807                                        cam_flags camflags,
808                                        u_int32_t sense_flags),
809                   cam_flags camflags, u_int32_t sense_flags,
810                   struct devstat *ds)
811 {
812         int error;
813  
814         error = 0;
815         
816         /*
817          * If the user has supplied a stats structure, and if we understand
818          * this particular type of ccb, record the transaction start.
819          */
820         if ((ds != NULL) && (ccb->ccb_h.func_code == XPT_SCSI_IO))
821                 devstat_start_transaction(ds);
822
823         xpt_action(ccb);
824  
825         do {
826                 cam_periph_ccbwait(ccb);
827                 if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
828                         error = 0;
829                 else if (error_routine != NULL)
830                         error = (*error_routine)(ccb, camflags, sense_flags);
831                 else
832                         error = 0;
833
834         } while (error == ERESTART);
835           
836         if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 
837                 cam_release_devq(ccb->ccb_h.path,
838                                  /* relsim_flags */0,
839                                  /* openings */0,
840                                  /* timeout */0,
841                                  /* getcount_only */ FALSE);
842
843         if ((ds != NULL) && (ccb->ccb_h.func_code == XPT_SCSI_IO))
844                 devstat_end_transaction(ds,
845                                         ccb->csio.dxfer_len,
846                                         ccb->csio.tag_action & 0xf,
847                                         ((ccb->ccb_h.flags & CAM_DIR_MASK) ==
848                                         CAM_DIR_NONE) ?  DEVSTAT_NO_DATA : 
849                                         (ccb->ccb_h.flags & CAM_DIR_OUT) ?
850                                         DEVSTAT_WRITE : 
851                                         DEVSTAT_READ);
852
853         return(error);
854 }
855
856 void
857 cam_freeze_devq(struct cam_path *path)
858 {
859         struct ccb_hdr ccb_h;
860
861         xpt_setup_ccb(&ccb_h, path, /*priority*/1);
862         ccb_h.func_code = XPT_NOOP;
863         ccb_h.flags = CAM_DEV_QFREEZE;
864         xpt_action((union ccb *)&ccb_h);
865 }
866
867 u_int32_t
868 cam_release_devq(struct cam_path *path, u_int32_t relsim_flags,
869                  u_int32_t openings, u_int32_t timeout,
870                  int getcount_only)
871 {
872         struct ccb_relsim crs;
873
874         xpt_setup_ccb(&crs.ccb_h, path,
875                       /*priority*/1);
876         crs.ccb_h.func_code = XPT_REL_SIMQ;
877         crs.ccb_h.flags = getcount_only ? CAM_DEV_QFREEZE : 0;
878         crs.release_flags = relsim_flags;
879         crs.openings = openings;
880         crs.release_timeout = timeout;
881         xpt_action((union ccb *)&crs);
882         return (crs.qfrozen_cnt);
883 }
884
885 #define saved_ccb_ptr ppriv_ptr0
886 static void
887 camperiphdone(struct cam_periph *periph, union ccb *done_ccb)
888 {
889         cam_status      status;
890         int             frozen;
891         int             sense;
892         struct scsi_start_stop_unit *scsi_cmd;
893         u_int32_t       relsim_flags, timeout;
894         u_int32_t       qfrozen_cnt;
895
896         status = done_ccb->ccb_h.status;
897         frozen = (status & CAM_DEV_QFRZN) != 0;
898         sense  = (status & CAM_AUTOSNS_VALID) != 0;
899         status &= CAM_STATUS_MASK;
900
901         timeout = 0;
902         relsim_flags = 0;
903
904         /* 
905          * Unfreeze the queue once if it is already frozen..
906          */
907         if (frozen != 0) {
908                 qfrozen_cnt = cam_release_devq(done_ccb->ccb_h.path,
909                                               /*relsim_flags*/0,
910                                               /*openings*/0,
911                                               /*timeout*/0,
912                                               /*getcount_only*/0);
913         }
914
915         switch (status) {
916
917         case CAM_REQ_CMP:
918
919                 /*
920                  * If we have successfully taken a device from the not
921                  * ready to ready state, re-scan the device and re-get the
922                  * inquiry information.  Many devices (mostly disks) don't
923                  * properly report their inquiry information unless they
924                  * are spun up.
925                  */
926                 if (done_ccb->ccb_h.func_code == XPT_SCSI_IO) {
927                         scsi_cmd = (struct scsi_start_stop_unit *)
928                                         &done_ccb->csio.cdb_io.cdb_bytes;
929
930                         if (scsi_cmd->opcode == START_STOP_UNIT)
931                                 xpt_async(AC_INQ_CHANGED,
932                                           done_ccb->ccb_h.path, NULL);
933                 }
934                 bcopy(done_ccb->ccb_h.saved_ccb_ptr, done_ccb,
935                       sizeof(union ccb));
936
937                 periph->flags &= ~CAM_PERIPH_RECOVERY_INPROG;
938
939                 xpt_action(done_ccb);
940
941                 break;
942         case CAM_SCSI_STATUS_ERROR:
943                 scsi_cmd = (struct scsi_start_stop_unit *)
944                                 &done_ccb->csio.cdb_io.cdb_bytes;
945                 if (sense != 0) {
946                         struct scsi_sense_data *sense;
947                         int    error_code, sense_key, asc, ascq;        
948
949                         sense = &done_ccb->csio.sense_data;
950                         scsi_extract_sense(sense, &error_code, 
951                                            &sense_key, &asc, &ascq);
952
953                         /*
954                          * If the error is "invalid field in CDB", 
955                          * and the load/eject flag is set, turn the 
956                          * flag off and try again.  This is just in 
957                          * case the drive in question barfs on the 
958                          * load eject flag.  The CAM code should set 
959                          * the load/eject flag by default for 
960                          * removable media.
961                          */
962
963                         /* XXX KDM 
964                          * Should we check to see what the specific
965                          * scsi status is??  Or does it not matter
966                          * since we already know that there was an
967                          * error, and we know what the specific
968                          * error code was, and we know what the
969                          * opcode is..
970                          */
971                         if ((scsi_cmd->opcode == START_STOP_UNIT) &&
972                             ((scsi_cmd->how & SSS_LOEJ) != 0) &&
973                              (asc == 0x24) && (ascq == 0x00) &&
974                              (done_ccb->ccb_h.retry_count > 0)) {
975
976                                 scsi_cmd->how &= ~SSS_LOEJ;
977
978                                 xpt_action(done_ccb);
979
980                         } else if (done_ccb->ccb_h.retry_count > 0) {
981                                 /*
982                                  * In this case, the error recovery
983                                  * command failed, but we've got 
984                                  * some retries left on it.  Give
985                                  * it another try.
986                                  */
987
988                                 /* set the timeout to .5 sec */
989                                 relsim_flags =
990                                         RELSIM_RELEASE_AFTER_TIMEOUT;
991                                 timeout = 500;
992
993                                 xpt_action(done_ccb);
994
995                                 break;
996
997                         } else {
998                                 /* 
999                                  * Copy the original CCB back and
1000                                  * send it back to the caller.
1001                                  */
1002                                 bcopy(done_ccb->ccb_h.saved_ccb_ptr,            
1003                                       done_ccb, sizeof(union ccb));
1004
1005                                 periph->flags &= ~CAM_PERIPH_RECOVERY_INPROG;
1006
1007                                 xpt_action(done_ccb);
1008                         }
1009                 } else {
1010                         /*
1011                          * Eh??  The command failed, but we don't
1012                          * have any sense.  What's up with that?
1013                          * Fire the CCB again to return it to the
1014                          * caller.
1015                          */
1016                         bcopy(done_ccb->ccb_h.saved_ccb_ptr,
1017                               done_ccb, sizeof(union ccb));
1018
1019                         periph->flags &= ~CAM_PERIPH_RECOVERY_INPROG;
1020
1021                         xpt_action(done_ccb);
1022
1023                 }
1024                 break;
1025         default:
1026                 bcopy(done_ccb->ccb_h.saved_ccb_ptr, done_ccb,
1027                       sizeof(union ccb));
1028
1029                 periph->flags &= ~CAM_PERIPH_RECOVERY_INPROG;
1030
1031                 xpt_action(done_ccb);
1032
1033                 break;
1034         }
1035
1036         /* decrement the retry count */
1037         if (done_ccb->ccb_h.retry_count > 0)
1038                 done_ccb->ccb_h.retry_count--;
1039
1040         qfrozen_cnt = cam_release_devq(done_ccb->ccb_h.path,
1041                                       /*relsim_flags*/relsim_flags,
1042                                       /*openings*/0,
1043                                       /*timeout*/timeout,
1044                                       /*getcount_only*/0);
1045 }
1046
1047 /*
1048  * Generic Async Event handler.  Peripheral drivers usually
1049  * filter out the events that require personal attention,
1050  * and leave the rest to this function.
1051  */
1052 void
1053 cam_periph_async(struct cam_periph *periph, u_int32_t code,
1054                  struct cam_path *path, void *arg)
1055 {
1056         switch (code) {
1057         case AC_LOST_DEVICE:
1058                 cam_periph_invalidate(periph);
1059                 break; 
1060         case AC_SENT_BDR:
1061         case AC_BUS_RESET:
1062         {
1063                 cam_periph_bus_settle(periph, SCSI_DELAY);
1064                 break;
1065         }
1066         default:
1067                 break;
1068         }
1069 }
1070
1071 void
1072 cam_periph_bus_settle(struct cam_periph *periph, u_int bus_settle)
1073 {
1074         struct ccb_getdevstats cgds;
1075
1076         xpt_setup_ccb(&cgds.ccb_h, periph->path, /*priority*/1);
1077         cgds.ccb_h.func_code = XPT_GDEV_STATS;
1078         xpt_action((union ccb *)&cgds);
1079         cam_periph_freeze_after_event(periph, &cgds.last_reset, bus_settle);
1080 }
1081
1082 void
1083 cam_periph_freeze_after_event(struct cam_periph *periph,
1084                               struct timeval* event_time, u_int duration_ms)
1085 {
1086         struct timeval delta;
1087         struct timeval duration_tv;
1088         int s;
1089
1090         s = splclock();
1091         microtime(&delta);
1092         splx(s);
1093         timevalsub(&delta, event_time);
1094         duration_tv.tv_sec = duration_ms / 1000;
1095         duration_tv.tv_usec = (duration_ms % 1000) * 1000;
1096         if (timevalcmp(&delta, &duration_tv, <)) {
1097                 timevalsub(&duration_tv, &delta);
1098
1099                 duration_ms = duration_tv.tv_sec * 1000;
1100                 duration_ms += duration_tv.tv_usec / 1000;
1101                 cam_freeze_devq(periph->path); 
1102                 cam_release_devq(periph->path,
1103                                 RELSIM_RELEASE_AFTER_TIMEOUT,
1104                                 /*reduction*/0,
1105                                 /*timeout*/duration_ms,
1106                                 /*getcount_only*/0);
1107         }
1108
1109 }
1110
1111 /*
1112  * Generic error handler.  Peripheral drivers usually filter
1113  * out the errors that they handle in a unique mannor, then
1114  * call this function.
1115  */
1116 int
1117 cam_periph_error(union ccb *ccb, cam_flags camflags,
1118                  u_int32_t sense_flags, union ccb *save_ccb)
1119 {
1120         cam_status status;
1121         int        frozen;
1122         int        sense;
1123         int        error;
1124         int        openings;
1125         int        retry;
1126         u_int32_t  relsim_flags;
1127         u_int32_t  timeout;
1128         
1129         status = ccb->ccb_h.status;
1130         frozen = (status & CAM_DEV_QFRZN) != 0;
1131         sense  = (status & CAM_AUTOSNS_VALID) != 0;
1132         status &= CAM_STATUS_MASK;
1133         relsim_flags = 0;
1134
1135         switch (status) {
1136         case CAM_REQ_CMP:
1137                 /* decrement the number of retries */
1138                 retry = ccb->ccb_h.retry_count > 0;
1139                 if (retry)
1140                         ccb->ccb_h.retry_count--;
1141                 error = 0;
1142                 break;
1143         case CAM_AUTOSENSE_FAIL:
1144         case CAM_SCSI_STATUS_ERROR:
1145
1146                 switch (ccb->csio.scsi_status) {
1147                 case SCSI_STATUS_OK:
1148                 case SCSI_STATUS_COND_MET:
1149                 case SCSI_STATUS_INTERMED:
1150                 case SCSI_STATUS_INTERMED_COND_MET:
1151                         error = 0;
1152                         break;
1153                 case SCSI_STATUS_CMD_TERMINATED:
1154                 case SCSI_STATUS_CHECK_COND:
1155                         if (sense != 0) {
1156                                 struct scsi_sense_data *sense;
1157                                 int    error_code, sense_key, asc, ascq;
1158                                 struct cam_periph *periph;
1159                                 scsi_sense_action err_action;
1160                                 struct ccb_getdev cgd;
1161
1162                                 sense = &ccb->csio.sense_data;
1163                                 scsi_extract_sense(sense, &error_code,
1164                                                    &sense_key, &asc, &ascq);
1165                                 periph = xpt_path_periph(ccb->ccb_h.path);
1166
1167                                 /*
1168                                  * Grab the inquiry data for this device.
1169                                  */
1170                                 xpt_setup_ccb(&cgd.ccb_h, ccb->ccb_h.path,
1171                                               /*priority*/ 1);
1172                                 cgd.ccb_h.func_code = XPT_GDEV_TYPE;
1173                                 xpt_action((union ccb *)&cgd);
1174
1175                                 err_action = scsi_error_action(asc, ascq, 
1176                                                                &cgd.inq_data);
1177
1178                                 /*
1179                                  * Send a Test Unit Ready to the device.
1180                                  * If the 'many' flag is set, we send 120
1181                                  * test unit ready commands, one every half 
1182                                  * second.  Otherwise, we just send one TUR.
1183                                  * We only want to do this if the retry 
1184                                  * count has not been exhausted.
1185                                  */
1186                                 if (((err_action & SS_MASK) == SS_TUR)
1187                                  && save_ccb != NULL 
1188                                  && ccb->ccb_h.retry_count > 0) {
1189
1190                                         /*
1191                                          * Since error recovery is already
1192                                          * in progress, don't attempt to
1193                                          * process this error.  It is probably
1194                                          * related to the error that caused
1195                                          * the currently active error recovery
1196                                          * action.  Also, we only have
1197                                          * space for one saved CCB, so if we
1198                                          * had two concurrent error recovery
1199                                          * actions, we would end up
1200                                          * over-writing one error recovery
1201                                          * CCB with another one.
1202                                          */
1203                                         if (periph->flags &
1204                                             CAM_PERIPH_RECOVERY_INPROG) {
1205                                                 error = ERESTART;
1206                                                 break;
1207                                         }
1208
1209                                         periph->flags |=
1210                                                 CAM_PERIPH_RECOVERY_INPROG;
1211
1212                                         /* decrement the number of retries */
1213                                         if ((err_action & 
1214                                              SSQ_DECREMENT_COUNT) != 0) {
1215                                                 retry = 1;
1216                                                 ccb->ccb_h.retry_count--;
1217                                         }
1218
1219                                         bcopy(ccb, save_ccb, sizeof(*save_ccb));
1220
1221                                         /*
1222                                          * We retry this one every half
1223                                          * second for a minute.  If the
1224                                          * device hasn't become ready in a
1225                                          * minute's time, it's unlikely to
1226                                          * ever become ready.  If the table
1227                                          * doesn't specify SSQ_MANY, we can
1228                                          * only try this once.  Oh well.
1229                                          */
1230                                         if ((err_action & SSQ_MANY) != 0)
1231                                                 scsi_test_unit_ready(&ccb->csio,
1232                                                                /*retries*/120,
1233                                                                camperiphdone,
1234                                                                MSG_SIMPLE_Q_TAG,
1235                                                                SSD_FULL_SIZE,
1236                                                                /*timeout*/5000);
1237                                         else
1238                                                 scsi_test_unit_ready(&ccb->csio,
1239                                                                /*retries*/1,
1240                                                                camperiphdone,
1241                                                                MSG_SIMPLE_Q_TAG,
1242                                                                SSD_FULL_SIZE,
1243                                                                /*timeout*/5000);
1244
1245                                         /* release the queue after .5 sec.  */
1246                                         relsim_flags = 
1247                                                 RELSIM_RELEASE_AFTER_TIMEOUT;
1248                                         timeout = 500;
1249                                         /*
1250                                          * Drop the priority to 0 so that 
1251                                          * we are the first to execute.  Also 
1252                                          * freeze the queue after this command 
1253                                          * is sent so that we can restore the 
1254                                          * old csio and have it queued in the 
1255                                          * proper order before we let normal 
1256                                          * transactions go to the drive.
1257                                          */
1258                                         ccb->ccb_h.pinfo.priority = 0;
1259                                         ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
1260
1261                                         /*
1262                                          * Save a pointer to the original
1263                                          * CCB in the new CCB.
1264                                          */
1265                                         ccb->ccb_h.saved_ccb_ptr = save_ccb;
1266
1267                                         error = ERESTART;
1268                                 }
1269                                 /*
1270                                  * Send a start unit command to the device,
1271                                  * and then retry the command.  We only 
1272                                  * want to do this if the retry count has 
1273                                  * not been exhausted.  If the user 
1274                                  * specified 0 retries, then we follow 
1275                                  * their request and do not retry.
1276                                  */
1277                                 else if (((err_action & SS_MASK) == SS_START)
1278                                       && save_ccb != NULL 
1279                                       && ccb->ccb_h.retry_count > 0) {
1280                                         int le;
1281
1282                                         /*
1283                                          * Only one error recovery action
1284                                          * at a time.  See above.
1285                                          */
1286                                         if (periph->flags &
1287                                             CAM_PERIPH_RECOVERY_INPROG) {
1288                                                 error = ERESTART;
1289                                                 break;
1290                                         }
1291
1292                                         periph->flags |=
1293                                                 CAM_PERIPH_RECOVERY_INPROG;
1294
1295                                         /* decrement the number of retries */
1296                                         retry = 1;
1297                                         ccb->ccb_h.retry_count--;
1298
1299                                         /*
1300                                          * Check for removable media and
1301                                          * set load/eject flag
1302                                          * appropriately.
1303                                          */
1304                                         if (SID_IS_REMOVABLE(&cgd.inq_data))
1305                                                 le = TRUE;
1306                                         else
1307                                                 le = FALSE;
1308
1309                                         /*
1310                                          * Attempt to start the drive up.
1311                                          *
1312                                          * Save the current ccb so it can 
1313                                          * be restored and retried once the 
1314                                          * drive is started up.
1315                                          */
1316                                         bcopy(ccb, save_ccb, sizeof(*save_ccb));
1317
1318                                         scsi_start_stop(&ccb->csio,
1319                                                         /*retries*/1,
1320                                                         camperiphdone,
1321                                                         MSG_SIMPLE_Q_TAG,
1322                                                         /*start*/TRUE,
1323                                                         /*load/eject*/le,
1324                                                         /*immediate*/FALSE,
1325                                                         SSD_FULL_SIZE,
1326                                                         /*timeout*/50000);
1327                                         /*
1328                                          * Drop the priority to 0 so that 
1329                                          * we are the first to execute.  Also 
1330                                          * freeze the queue after this command 
1331                                          * is sent so that we can restore the 
1332                                          * old csio and have it queued in the 
1333                                          * proper order before we let normal 
1334                                          * transactions go to the drive.
1335                                          */
1336                                         ccb->ccb_h.pinfo.priority = 0;
1337                                         ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
1338
1339                                         /*
1340                                          * Save a pointer to the original
1341                                          * CCB in the new CCB.
1342                                          */
1343                                         ccb->ccb_h.saved_ccb_ptr = save_ccb;
1344
1345                                         error = ERESTART;
1346                                 } else if ((sense_flags & SF_RETRY_UA) != 0) {
1347                                         /*
1348                                          * XXX KDM this is a *horrible*
1349                                          * hack.  
1350                                          */
1351                                         error = scsi_interpret_sense(ccb,
1352                                                                   sense_flags,
1353                                                                   &relsim_flags,
1354                                                                   &openings,
1355                                                                   &timeout,
1356                                                                   err_action);
1357                                 } 
1358
1359                                 /*
1360                                  * Theoretically, this code should send a
1361                                  * test unit ready to the given device, and 
1362                                  * if it returns and error, send a start 
1363                                  * unit command.  Since we don't yet have
1364                                  * the capability to do two-command error
1365                                  * recovery, just send a start unit.
1366                                  * XXX KDM fix this!
1367                                  */
1368                                 else if (((err_action & SS_MASK) == SS_TURSTART)
1369                                       && save_ccb != NULL
1370                                       && ccb->ccb_h.retry_count > 0) {
1371                                         int le;
1372
1373                                         /*
1374                                          * Only one error recovery action
1375                                          * at a time.  See above.
1376                                          */
1377                                         if (periph->flags &
1378                                             CAM_PERIPH_RECOVERY_INPROG) {
1379                                                 error = ERESTART;
1380                                                 break;
1381                                         }
1382
1383                                         periph->flags |=
1384                                                 CAM_PERIPH_RECOVERY_INPROG;
1385
1386                                         /* decrement the number of retries */
1387                                         retry = 1;
1388                                         ccb->ccb_h.retry_count--;
1389
1390                                         /*
1391                                          * Check for removable media and
1392                                          * set load/eject flag
1393                                          * appropriately.
1394                                          */
1395                                         if (SID_IS_REMOVABLE(&cgd.inq_data))
1396                                                 le = TRUE;
1397                                         else
1398                                                 le = FALSE;
1399
1400                                         /*
1401                                          * Attempt to start the drive up.
1402                                          *
1403                                          * Save the current ccb so it can 
1404                                          * be restored and retried once the 
1405                                          * drive is started up.
1406                                          */
1407                                         bcopy(ccb, save_ccb, sizeof(*save_ccb));
1408
1409                                         scsi_start_stop(&ccb->csio,
1410                                                         /*retries*/1,
1411                                                         camperiphdone,
1412                                                         MSG_SIMPLE_Q_TAG,
1413                                                         /*start*/TRUE,
1414                                                         /*load/eject*/le,
1415                                                         /*immediate*/FALSE,
1416                                                         SSD_FULL_SIZE,
1417                                                         /*timeout*/50000);
1418
1419                                         /* release the queue after .5 sec.  */
1420                                         relsim_flags = 
1421                                                 RELSIM_RELEASE_AFTER_TIMEOUT;
1422                                         timeout = 500;
1423                                         /*
1424                                          * Drop the priority to 0 so that 
1425                                          * we are the first to execute.  Also 
1426                                          * freeze the queue after this command 
1427                                          * is sent so that we can restore the 
1428                                          * old csio and have it queued in the 
1429                                          * proper order before we let normal 
1430                                          * transactions go to the drive.
1431                                          */
1432                                         ccb->ccb_h.pinfo.priority = 0;
1433                                         ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
1434
1435                                         /*
1436                                          * Save a pointer to the original
1437                                          * CCB in the new CCB.
1438                                          */
1439                                         ccb->ccb_h.saved_ccb_ptr = save_ccb;
1440
1441                                         error = ERESTART;
1442                                 } else {
1443                                         error = scsi_interpret_sense(ccb,
1444                                                                   sense_flags,
1445                                                                   &relsim_flags,
1446                                                                   &openings,
1447                                                                   &timeout,
1448                                                                   err_action);
1449                                 }
1450                         } else if (ccb->csio.scsi_status == 
1451                                    SCSI_STATUS_CHECK_COND
1452                                 && status != CAM_AUTOSENSE_FAIL) {
1453                                 /* no point in decrementing the retry count */
1454                                 panic("cam_periph_error: scsi status of "
1455                                       "CHECK COND returned but no sense "
1456                                       "information is availible.  "
1457                                       "Controller should have returned "
1458                                       "CAM_AUTOSENSE_FAILED");
1459                                 /* NOTREACHED */
1460                                 error = EIO;
1461                         } else if (ccb->ccb_h.retry_count == 0) {
1462                                 /*
1463                                  * XXX KDM shouldn't there be a better
1464                                  * argument to return??
1465                                  */
1466                                 error = EIO;
1467                         } else {
1468                                 /* decrement the number of retries */
1469                                 retry = ccb->ccb_h.retry_count > 0;
1470                                 if (retry)
1471                                         ccb->ccb_h.retry_count--;
1472                                 /*
1473                                  * If it was aborted with no
1474                                  * clue as to the reason, just
1475                                  * retry it again.
1476                                  */
1477                                 error = ERESTART;
1478                         }
1479                         break;
1480                 case SCSI_STATUS_QUEUE_FULL:
1481                 {
1482                         /* no decrement */
1483                         struct ccb_getdevstats cgds;
1484
1485                         /*
1486                          * First off, find out what the current
1487                          * transaction counts are.
1488                          */
1489                         xpt_setup_ccb(&cgds.ccb_h,
1490                                       ccb->ccb_h.path,
1491                                       /*priority*/1);
1492                         cgds.ccb_h.func_code = XPT_GDEV_STATS;
1493                         xpt_action((union ccb *)&cgds);
1494
1495                         /*
1496                          * If we were the only transaction active, treat
1497                          * the QUEUE FULL as if it were a BUSY condition.
1498                          */
1499                         if (cgds.dev_active != 0) {
1500                                 int total_openings;
1501
1502                                 /*
1503                                  * Reduce the number of openings to
1504                                  * be 1 less than the amount it took
1505                                  * to get a queue full bounded by the
1506                                  * minimum allowed tag count for this
1507                                  * device.
1508                                  */
1509                                 total_openings =
1510                                     cgds.dev_active+cgds.dev_openings;
1511                                 openings = cgds.dev_active;
1512                                 if (openings < cgds.mintags)
1513                                         openings = cgds.mintags;
1514                                 if (openings < total_openings)
1515                                         relsim_flags = RELSIM_ADJUST_OPENINGS;
1516                                 else {
1517                                         /*
1518                                          * Some devices report queue full for
1519                                          * temporary resource shortages.  For
1520                                          * this reason, we allow a minimum
1521                                          * tag count to be entered via a
1522                                          * quirk entry to prevent the queue
1523                                          * count on these devices from falling
1524                                          * to a pessimisticly low value.  We
1525                                          * still wait for the next successful
1526                                          * completion, however, before queueing
1527                                          * more transactions to the device.
1528                                          */
1529                                         relsim_flags =
1530                                             RELSIM_RELEASE_AFTER_CMDCMPLT;
1531                                 }
1532                                 timeout = 0;
1533                                 error = ERESTART;
1534                                 break;
1535                         }
1536                         /* FALLTHROUGH */
1537                 }
1538                 case SCSI_STATUS_BUSY:
1539                         /*
1540                          * Restart the queue after either another
1541                          * command completes or a 1 second timeout.
1542                          * If we have any retries left, that is.
1543                          */
1544                         retry = ccb->ccb_h.retry_count > 0;
1545                         if (retry) {
1546                                 ccb->ccb_h.retry_count--;
1547                                 error = ERESTART;
1548                                 relsim_flags = RELSIM_RELEASE_AFTER_TIMEOUT
1549                                              | RELSIM_RELEASE_AFTER_CMDCMPLT;
1550                                 timeout = 1000;
1551                         } else {
1552                                 error = EIO;
1553                         }
1554                         break;
1555                 case SCSI_STATUS_RESERV_CONFLICT:
1556                         error = EIO;
1557                         break;
1558                 default:
1559                         error = EIO;
1560                         break;
1561                 }
1562                 break;
1563         case CAM_REQ_CMP_ERR:
1564         case CAM_CMD_TIMEOUT:
1565         case CAM_UNEXP_BUSFREE:
1566         case CAM_UNCOR_PARITY:
1567         case CAM_DATA_RUN_ERR:
1568                 /* decrement the number of retries */
1569                 retry = ccb->ccb_h.retry_count > 0;
1570                 if (retry) {
1571                         ccb->ccb_h.retry_count--;
1572                         error = ERESTART;
1573                 } else {
1574                         error = EIO;
1575                 }
1576                 break;
1577         case CAM_UA_ABORT:
1578         case CAM_UA_TERMIO:
1579         case CAM_MSG_REJECT_REC:
1580                 /* XXX Don't know that these are correct */
1581                 error = EIO;
1582                 break;
1583         case CAM_SEL_TIMEOUT:
1584         {
1585                 /*
1586                  * XXX
1587                  * A single selection timeout should not be enough
1588                  * to invalidate a device.  We should retry for multiple
1589                  * seconds assuming this isn't a probe.  We'll probably
1590                  * need a special flag for that.
1591                  */
1592 #if 0
1593                 struct cam_path *newpath;
1594
1595                 /* Should we do more if we can't create the path?? */
1596                 if (xpt_create_path(&newpath, xpt_path_periph(ccb->ccb_h.path),
1597                                     xpt_path_path_id(ccb->ccb_h.path),
1598                                     xpt_path_target_id(ccb->ccb_h.path),
1599                                     CAM_LUN_WILDCARD) != CAM_REQ_CMP) 
1600                         break;
1601                 /*
1602                  * Let peripheral drivers know that this device has gone
1603                  * away.
1604                  */
1605                 xpt_async(AC_LOST_DEVICE, newpath, NULL);
1606                 xpt_free_path(newpath);
1607 #endif
1608                 if ((sense_flags & SF_RETRY_SELTO) != 0) {
1609                         retry = ccb->ccb_h.retry_count > 0;
1610                         if (retry) {
1611                                 ccb->ccb_h.retry_count--;
1612                                 error = ERESTART;
1613                                 /*
1614                                  * Wait half a second to give the device
1615                                  * time to recover before we try again.
1616                                  */
1617                                 relsim_flags = RELSIM_RELEASE_AFTER_TIMEOUT;
1618                                 timeout = 500;
1619                         } else {
1620                                 error = ENXIO;
1621                         }
1622                 } else {
1623                         error = ENXIO;
1624                 }
1625                 break;
1626         }
1627         case CAM_REQ_INVALID:
1628         case CAM_PATH_INVALID:
1629         case CAM_DEV_NOT_THERE:
1630         case CAM_NO_HBA:
1631         case CAM_PROVIDE_FAIL:
1632         case CAM_REQ_TOO_BIG:           
1633                 error = EINVAL;
1634                 break;
1635         case CAM_SCSI_BUS_RESET:
1636         case CAM_BDR_SENT:              
1637         case CAM_REQUEUE_REQ:
1638                 /* Unconditional requeue, dammit */
1639                 error = ERESTART;
1640                 break;
1641         case CAM_RESRC_UNAVAIL:
1642         case CAM_BUSY:
1643                 /* timeout??? */
1644         default:
1645                 /* decrement the number of retries */
1646                 retry = ccb->ccb_h.retry_count > 0;
1647                 if (retry) {
1648                         ccb->ccb_h.retry_count--;
1649                         error = ERESTART;
1650                 } else {
1651                         /* Check the sense codes */
1652                         error = EIO;
1653                 }
1654                 break;
1655         }
1656
1657         /* Attempt a retry */
1658         if (error == ERESTART || error == 0) {  
1659                 if (frozen != 0)
1660                         ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
1661
1662                 if (error == ERESTART)
1663                         xpt_action(ccb);
1664                 
1665                 if (frozen != 0) {
1666                         cam_release_devq(ccb->ccb_h.path,
1667                                          relsim_flags,
1668                                          openings,
1669                                          timeout,
1670                                          /*getcount_only*/0);
1671                 }
1672         }
1673
1674
1675         return (error);
1676 }