[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]

FreeBSD/Linux Kernel Cross Reference
sys/cam/cam_periph.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD70  -  FREEBSD6  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  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 
 30 #include <sys/cdefs.h>
 31 __FBSDID("$FreeBSD: src/sys/cam/cam_periph.c,v 1.70 2008/02/12 11:07:33 raj Exp $");
 32 
 33 #include <sys/param.h>
 34 #include <sys/systm.h>
 35 #include <sys/types.h>
 36 #include <sys/malloc.h>
 37 #include <sys/kernel.h>
 38 #include <sys/linker_set.h>
 39 #include <sys/bio.h>
 40 #include <sys/lock.h>
 41 #include <sys/mutex.h>
 42 #include <sys/buf.h>
 43 #include <sys/proc.h>
 44 #include <sys/devicestat.h>
 45 #include <sys/bus.h>
 46 #include <vm/vm.h>
 47 #include <vm/vm_extern.h>
 48 
 49 #include <cam/cam.h>
 50 #include <cam/cam_ccb.h>
 51 #include <cam/cam_xpt_periph.h>
 52 #include <cam/cam_periph.h>
 53 #include <cam/cam_debug.h>
 54 #include <cam/cam_sim.h>
 55 
 56 #include <cam/scsi/scsi_all.h>
 57 #include <cam/scsi/scsi_message.h>
 58 #include <cam/scsi/scsi_pass.h>
 59 
 60 static  u_int           camperiphnextunit(struct periph_driver *p_drv,
 61                                           u_int newunit, int wired,
 62                                           path_id_t pathid, target_id_t target,
 63                                           lun_id_t lun);
 64 static  u_int           camperiphunit(struct periph_driver *p_drv,
 65                                       path_id_t pathid, target_id_t target,
 66                                       lun_id_t lun); 
 67 static  void            camperiphdone(struct cam_periph *periph, 
 68                                         union ccb *done_ccb);
 69 static  void            camperiphfree(struct cam_periph *periph);
 70 static int              camperiphscsistatuserror(union ccb *ccb,
 71                                                  cam_flags camflags,
 72                                                  u_int32_t sense_flags,
 73                                                  union ccb *save_ccb,
 74                                                  int *openings,
 75                                                  u_int32_t *relsim_flags,
 76                                                  u_int32_t *timeout);
 77 static  int             camperiphscsisenseerror(union ccb *ccb,
 78                                                 cam_flags camflags,
 79                                                 u_int32_t sense_flags,
 80                                                 union ccb *save_ccb,
 81                                                 int *openings,
 82                                                 u_int32_t *relsim_flags,
 83                                                 u_int32_t *timeout);
 84 
 85 static int nperiph_drivers;
 86 struct periph_driver **periph_drivers;
 87 
 88 MALLOC_DEFINE(M_CAMPERIPH, "CAM periph", "CAM peripheral buffers");
 89 
 90 static int periph_selto_delay = 1000;
 91 TUNABLE_INT("kern.cam.periph_selto_delay", &periph_selto_delay);
 92 static int periph_noresrc_delay = 500;
 93 TUNABLE_INT("kern.cam.periph_noresrc_delay", &periph_noresrc_delay);
 94 static int periph_busy_delay = 500;
 95 TUNABLE_INT("kern.cam.periph_busy_delay", &periph_busy_delay);
 96 
 97 
 98 void
 99 periphdriver_register(void *data)
100 {
101         struct periph_driver **newdrivers, **old;
102         int ndrivers;
103 
104         ndrivers = nperiph_drivers + 2;
105         newdrivers = malloc(sizeof(*newdrivers) * ndrivers, M_CAMPERIPH,
106                             M_WAITOK);
107         if (periph_drivers)
108                 bcopy(periph_drivers, newdrivers,
109                       sizeof(*newdrivers) * nperiph_drivers);
110         newdrivers[nperiph_drivers] = (struct periph_driver *)data;
111         newdrivers[nperiph_drivers + 1] = NULL;
112         old = periph_drivers;
113         periph_drivers = newdrivers;
114         if (old)
115                 free(old, M_CAMPERIPH);
116         nperiph_drivers++;
117 }
118 
119 cam_status
120 cam_periph_alloc(periph_ctor_t *periph_ctor,
121                  periph_oninv_t *periph_oninvalidate,
122                  periph_dtor_t *periph_dtor, periph_start_t *periph_start,
123                  char *name, cam_periph_type type, struct cam_path *path,
124                  ac_callback_t *ac_callback, ac_code code, void *arg)
125 {
126         struct          periph_driver **p_drv;
127         struct          cam_sim *sim;
128         struct          cam_periph *periph;
129         struct          cam_periph *cur_periph;
130         path_id_t       path_id;
131         target_id_t     target_id;
132         lun_id_t        lun_id;
133         cam_status      status;
134         u_int           init_level;
135 
136         init_level = 0;
137         /*
138          * Handle Hot-Plug scenarios.  If there is already a peripheral
139          * of our type assigned to this path, we are likely waiting for
140          * final close on an old, invalidated, peripheral.  If this is
141          * the case, queue up a deferred call to the peripheral's async
142          * handler.  If it looks like a mistaken re-allocation, complain.
143          */
144         if ((periph = cam_periph_find(path, name)) != NULL) {
145 
146                 if ((periph->flags & CAM_PERIPH_INVALID) != 0
147                  && (periph->flags & CAM_PERIPH_NEW_DEV_FOUND) == 0) {
148                         periph->flags |= CAM_PERIPH_NEW_DEV_FOUND;
149                         periph->deferred_callback = ac_callback;
150                         periph->deferred_ac = code;
151                         return (CAM_REQ_INPROG);
152                 } else {
153                         printf("cam_periph_alloc: attempt to re-allocate "
154                                "valid device %s%d rejected\n",
155                                periph->periph_name, periph->unit_number);
156                 }
157                 return (CAM_REQ_INVALID);
158         }
159         
160         periph = (struct cam_periph *)malloc(sizeof(*periph), M_CAMPERIPH,
161                                              M_NOWAIT);
162 
163         if (periph == NULL)
164                 return (CAM_RESRC_UNAVAIL);
165         
166         init_level++;
167 
168         xpt_lock_buses();
169         for (p_drv = periph_drivers; *p_drv != NULL; p_drv++) {
170                 if (strcmp((*p_drv)->driver_name, name) == 0)
171                         break;
172         }
173         xpt_unlock_buses();
174 
175         sim = xpt_path_sim(path);
176         path_id = xpt_path_path_id(path);
177         target_id = xpt_path_target_id(path);
178         lun_id = xpt_path_lun_id(path);
179         bzero(periph, sizeof(*periph));
180         cam_init_pinfo(&periph->pinfo);
181         periph->periph_start = periph_start;
182         periph->periph_dtor = periph_dtor;
183         periph->periph_oninval = periph_oninvalidate;
184         periph->type = type;
185         periph->periph_name = name;
186         periph->unit_number = camperiphunit(*p_drv, path_id, target_id, lun_id);
187         periph->immediate_priority = CAM_PRIORITY_NONE;
188         periph->refcount = 0;
189         periph->sim = sim;
190         SLIST_INIT(&periph->ccb_list);
191         status = xpt_create_path(&path, periph, path_id, target_id, lun_id);
192         if (status != CAM_REQ_CMP)
193                 goto failure;
194 
195         periph->path = path;
196         init_level++;
197 
198         status = xpt_add_periph(periph);
199 
200         if (status != CAM_REQ_CMP)
201                 goto failure;
202 
203         cur_periph = TAILQ_FIRST(&(*p_drv)->units);
204         while (cur_periph != NULL
205             && cur_periph->unit_number < periph->unit_number)
206                 cur_periph = TAILQ_NEXT(cur_periph, unit_links);
207 
208         if (cur_periph != NULL)
209                 TAILQ_INSERT_BEFORE(cur_periph, periph, unit_links);
210         else {
211                 TAILQ_INSERT_TAIL(&(*p_drv)->units, periph, unit_links);
212                 (*p_drv)->generation++;
213         }
214 
215         init_level++;
216 
217         status = periph_ctor(periph, arg);
218 
219         if (status == CAM_REQ_CMP)
220                 init_level++;
221 
222 failure:
223         switch (init_level) {
224         case 4:
225                 /* Initialized successfully */
226                 break;
227         case 3:
228                 TAILQ_REMOVE(&(*p_drv)->units, periph, unit_links);
229                 xpt_remove_periph(periph);
230                 /* FALLTHROUGH */
231         case 2:
232                 xpt_free_path(periph->path);
233                 /* FALLTHROUGH */
234         case 1:
235                 free(periph, M_CAMPERIPH);
236                 /* FALLTHROUGH */
237         case 0:
238                 /* No cleanup to perform. */
239                 break;
240         default:
241                 panic("cam_periph_alloc: Unkown init level");
242         }
243         return(status);
244 }
245 
246 /*
247  * Find a peripheral structure with the specified path, target, lun, 
248  * and (optionally) type.  If the name is NULL, this function will return
249  * the first peripheral driver that matches the specified path.
250  */
251 struct cam_periph *
252 cam_periph_find(struct cam_path *path, char *name)
253 {
254         struct periph_driver **p_drv;
255         struct cam_periph *periph;
256 
257         xpt_lock_buses();
258         for (p_drv = periph_drivers; *p_drv != NULL; p_drv++) {
259 
260                 if (name != NULL && (strcmp((*p_drv)->driver_name, name) != 0))
261                         continue;
262 
263                 TAILQ_FOREACH(periph, &(*p_drv)->units, unit_links) {
264                         if (xpt_path_comp(periph->path, path) == 0) {
265                                 xpt_unlock_buses();
266                                 return(periph);
267                         }
268                 }
269                 if (name != NULL) {
270                         xpt_unlock_buses();
271                         return(NULL);
272                 }
273         }
274         xpt_unlock_buses();
275         return(NULL);
276 }
277 
278 cam_status
279 cam_periph_acquire(struct cam_periph *periph)
280 {
281 
282         if (periph == NULL)
283                 return(CAM_REQ_CMP_ERR);
284 
285         xpt_lock_buses();
286         periph->refcount++;
287         xpt_unlock_buses();
288 
289         return(CAM_REQ_CMP);
290 }
291 
292 void
293 cam_periph_release(struct cam_periph *periph)
294 {
295 
296         if (periph == NULL)
297                 return;
298 
299         xpt_lock_buses();
300         if ((--periph->refcount == 0)
301          && (periph->flags & CAM_PERIPH_INVALID)) {
302                 camperiphfree(periph);
303         }
304         xpt_unlock_buses();
305 
306 }
307 
308 int
309 cam_periph_hold(struct cam_periph *periph, int priority)
310 {
311         struct mtx *mtx;
312         int error;
313 
314         mtx_assert(periph->sim->mtx, MA_OWNED);
315 
316         /*
317          * Increment the reference count on the peripheral
318          * while we wait for our lock attempt to succeed
319          * to ensure the peripheral doesn't disappear out
320          * from user us while we sleep.
321          */
322 
323         if (cam_periph_acquire(periph) != CAM_REQ_CMP)
324                 return (ENXIO);
325 
326         mtx = periph->sim->mtx;
327         if (mtx == &Giant)
328                 mtx = NULL;
329 
330         while ((periph->flags & CAM_PERIPH_LOCKED) != 0) {
331                 periph->flags |= CAM_PERIPH_LOCK_WANTED;
332                 if ((error = msleep(periph, mtx, priority, "caplck", 0)) != 0) {
333                         cam_periph_release(periph);
334                         return (error);
335                 }
336         }
337 
338         periph->flags |= CAM_PERIPH_LOCKED;
339         return (0);
340 }
341 
342 void
343 cam_periph_unhold(struct cam_periph *periph)
344 {
345 
346         mtx_assert(periph->sim->mtx, MA_OWNED);
347 
348         periph->flags &= ~CAM_PERIPH_LOCKED;
349         if ((periph->flags & CAM_PERIPH_LOCK_WANTED) != 0) {
350                 periph->flags &= ~CAM_PERIPH_LOCK_WANTED;
351                 wakeup(periph);
352         }
353 
354         cam_periph_release(periph);
355 }
356 
357 /*
358  * Look for the next unit number that is not currently in use for this
359  * peripheral type starting at "newunit".  Also exclude unit numbers that
360  * are reserved by for future "hardwiring" unless we already know that this
361  * is a potential wired device.  Only assume that the device is "wired" the
362  * first time through the loop since after that we'll be looking at unit
363  * numbers that did not match a wiring entry.
364  */
365 static u_int
366 camperiphnextunit(struct periph_driver *p_drv, u_int newunit, int wired,
367                   path_id_t pathid, target_id_t target, lun_id_t lun)
368 {
369         struct  cam_periph *periph;
370         char    *periph_name;
371         int     i, val, dunit, r;
372         const char *dname, *strval;
373 
374         periph_name = p_drv->driver_name;
375         for (;;newunit++) {
376 
377                 for (periph = TAILQ_FIRST(&p_drv->units);
378                      periph != NULL && periph->unit_number != newunit;
379                      periph = TAILQ_NEXT(periph, unit_links))
380                         ;
381 
382                 if (periph != NULL && periph->unit_number == newunit) {
383                         if (wired != 0) {
384                                 xpt_print(periph->path, "Duplicate Wired "
385                                     "Device entry!\n");
386                                 xpt_print(periph->path, "Second device (%s "
387                                     "device at scbus%d target %d lun %d) will "
388                                     "not be wired\n", periph_name, pathid,
389                                     target, lun);
390                                 wired = 0;
391                         }
392                         continue;
393                 }
394                 if (wired)
395                         break;
396 
397                 /*
398                  * Don't match entries like "da 4" as a wired down
399                  * device, but do match entries like "da 4 target 5"
400                  * or even "da 4 scbus 1". 
401                  */
402                 i = 0;
403                 dname = periph_name;
404                 for (;;) {
405                         r = resource_find_dev(&i, dname, &dunit, NULL, NULL);
406                         if (r != 0)
407                                 break;
408                         /* if no "target" and no specific scbus, skip */
409                         if (resource_int_value(dname, dunit, "target", &val) &&
410                             (resource_string_value(dname, dunit, "at",&strval)||
411                              strcmp(strval, "scbus") == 0))
412                                 continue;
413                         if (newunit == dunit)
414                                 break;
415                 }
416                 if (r != 0)
417                         break;
418         }
419         return (newunit);
420 }
421 
422 static u_int
423 camperiphunit(struct periph_driver *p_drv, path_id_t pathid,
424               target_id_t target, lun_id_t lun)
425 {
426         u_int   unit;
427         int     wired, i, val, dunit;
428         const char *dname, *strval;
429         char    pathbuf[32], *periph_name;
430 
431         periph_name = p_drv->driver_name;
432         snprintf(pathbuf, sizeof(pathbuf), "scbus%d", pathid);
433         unit = 0;
434         i = 0;
435         dname = periph_name;
436         for (wired = 0; resource_find_dev(&i, dname, &dunit, NULL, NULL) == 0;
437              wired = 0) {
438                 if (resource_string_value(dname, dunit, "at", &strval) == 0) {
439                         if (strcmp(strval, pathbuf) != 0)
440                                 continue;
441                         wired++;
442                 }
443                 if (resource_int_value(dname, dunit, "target", &val) == 0) {
444                         if (val != target)
445                                 continue;
446                         wired++;
447                 }
448                 if (resource_int_value(dname, dunit, "lun", &val) == 0) {
449                         if (val != lun)
450                                 continue;
451                         wired++;
452                 }
453                 if (wired != 0) {
454                         unit = dunit;
455                         break;
456                 }
457         }
458 
459         /*
460          * Either start from 0 looking for the next unit or from
461          * the unit number given in the resource config.  This way,
462          * if we have wildcard matches, we don't return the same
463          * unit number twice.
464          */
465         unit = camperiphnextunit(p_drv, unit, wired, pathid, target, lun);
466 
467         return (unit);
468 }
469 
470 void
471 cam_periph_invalidate(struct cam_periph *periph)
472 {
473 
474         /*
475          * We only call this routine the first time a peripheral is
476          * invalidated.
477          */
478         if (((periph->flags & CAM_PERIPH_INVALID) == 0)
479          && (periph->periph_oninval != NULL))
480                 periph->periph_oninval(periph);
481 
482         periph->flags |= CAM_PERIPH_INVALID;
483         periph->flags &= ~CAM_PERIPH_NEW_DEV_FOUND;
484 
485         xpt_lock_buses();
486         if (periph->refcount == 0)
487                 camperiphfree(periph);
488         else if (periph->refcount < 0)
489                 printf("cam_invalidate_periph: refcount < 0!!\n");
490         xpt_unlock_buses();
491 }
492 
493 static void
494 camperiphfree(struct cam_periph *periph)
495 {
496         struct periph_driver **p_drv;
497 
498         for (p_drv = periph_drivers; *p_drv != NULL; p_drv++) {
499                 if (strcmp((*p_drv)->driver_name, periph->periph_name) == 0)
500                         break;
501         }
502         if (*p_drv == NULL) {
503                 printf("camperiphfree: attempt to free non-existant periph\n");
504                 return;
505         }
506 
507         TAILQ_REMOVE(&(*p_drv)->units, periph, unit_links);
508         (*p_drv)->generation++;
509         xpt_unlock_buses();
510 
511         if (periph->periph_dtor != NULL)
512                 periph->periph_dtor(periph);
513         xpt_remove_periph(periph);
514 
515         if (periph->flags & CAM_PERIPH_NEW_DEV_FOUND) {
516                 union ccb ccb;
517                 void *arg;
518 
519                 switch (periph->deferred_ac) {
520                 case AC_FOUND_DEVICE:
521                         ccb.ccb_h.func_code = XPT_GDEV_TYPE;
522                         xpt_setup_ccb(&ccb.ccb_h, periph->path, /*priority*/ 1);
523                         xpt_action(&ccb);
524                         arg = &ccb;
525                         break;
526                 case AC_PATH_REGISTERED:
527                         ccb.ccb_h.func_code = XPT_PATH_INQ;
528                         xpt_setup_ccb(&ccb.ccb_h, periph->path, /*priority*/ 1);
529                         xpt_action(&ccb);
530                         arg = &ccb;
531                         break;
532                 default:
533                         arg = NULL;
534                         break;
535                 }
536                 periph->deferred_callback(NULL, periph->deferred_ac,
537                                           periph->path, arg);
538         }
539         xpt_free_path(periph->path);
540         free(periph, M_CAMPERIPH);
541         xpt_lock_buses();
542 }
543 
544 /*
545  * Map user virtual pointers into kernel virtual address space, so we can
546  * access the memory.  This won't work on physical pointers, for now it's
547  * up to the caller to check for that.  (XXX KDM -- should we do that here
548  * instead?)  This also only works for up to MAXPHYS memory.  Since we use
549  * buffers to map stuff in and out, we're limited to the buffer size.
550  */
551 int
552 cam_periph_mapmem(union ccb *ccb, struct cam_periph_map_info *mapinfo)
553 {
554         int numbufs, i, j;
555         int flags[CAM_PERIPH_MAXMAPS];
556         u_int8_t **data_ptrs[CAM_PERIPH_MAXMAPS];
557         u_int32_t lengths[CAM_PERIPH_MAXMAPS];
558         u_int32_t dirs[CAM_PERIPH_MAXMAPS];
559 
560         switch(ccb->ccb_h.func_code) {
561         case XPT_DEV_MATCH:
562                 if (ccb->cdm.match_buf_len == 0) {
563                         printf("cam_periph_mapmem: invalid match buffer "
564                                "length 0\n");
565                         return(EINVAL);
566                 }
567                 if (ccb->cdm.pattern_buf_len > 0) {
568                         data_ptrs[0] = (u_int8_t **)&ccb->cdm.patterns;
569                         lengths[0] = ccb->cdm.pattern_buf_len;
570                         dirs[0] = CAM_DIR_OUT;
571                         data_ptrs[1] = (u_int8_t **)&ccb->cdm.matches;
572                         lengths[1] = ccb->cdm.match_buf_len;
573                         dirs[1] = CAM_DIR_IN;
574                         numbufs = 2;
575                 } else {
576                         data_ptrs[0] = (u_int8_t **)&ccb->cdm.matches;
577                         lengths[0] = ccb->cdm.match_buf_len;
578                         dirs[0] = CAM_DIR_IN;
579                         numbufs = 1;
580                 }
581                 break;
582         case XPT_SCSI_IO:
583         case XPT_CONT_TARGET_IO:
584                 if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE)
585                         return(0);
586 
587                 data_ptrs[0] = &ccb->csio.data_ptr;
588                 lengths[0] = ccb->csio.dxfer_len;
589                 dirs[0] = ccb->ccb_h.flags & CAM_DIR_MASK;
590                 numbufs = 1;
591                 break;
592         default:
593                 return(EINVAL);
594                 break; /* NOTREACHED */
595         }
596 
597         /*
598          * Check the transfer length and permissions first, so we don't
599          * have to unmap any previously mapped buffers.
600          */
601         for (i = 0; i < numbufs; i++) {
602 
603                 flags[i] = 0;
604 
605                 /*
606                  * The userland data pointer passed in may not be page
607                  * aligned.  vmapbuf() truncates the address to a page
608                  * boundary, so if the address isn't page aligned, we'll
609                  * need enough space for the given transfer length, plus
610                  * whatever extra space is necessary to make it to the page
611                  * boundary.
612                  */
613                 if ((lengths[i] +
614                     (((vm_offset_t)(*data_ptrs[i])) & PAGE_MASK)) > DFLTPHYS){
615                         printf("cam_periph_mapmem: attempt to map %lu bytes, "
616                                "which is greater than DFLTPHYS(%d)\n",
617                                (long)(lengths[i] +
618                                (((vm_offset_t)(*data_ptrs[i])) & PAGE_MASK)),
619                                DFLTPHYS);
620                         return(E2BIG);
621                 }
622 
623                 if (dirs[i] & CAM_DIR_OUT) {
624                         flags[i] = BIO_WRITE;
625                 }
626 
627                 if (dirs[i] & CAM_DIR_IN) {
628                         flags[i] = BIO_READ;
629                 }
630 
631         }
632 
633         /* this keeps the current process from getting swapped */
634         /*
635          * XXX KDM should I use P_NOSWAP instead?
636          */
637         PHOLD(curproc);
638 
639         for (i = 0; i < numbufs; i++) {
640                 /*
641                  * Get the buffer.
642                  */
643                 mapinfo->bp[i] = getpbuf(NULL);
644 
645                 /* save the buffer's data address */
646                 mapinfo->bp[i]->b_saveaddr = mapinfo->bp[i]->b_data;
647 
648                 /* put our pointer in the data slot */
649                 mapinfo->bp[i]->b_data = *data_ptrs[i];
650 
651                 /* set the transfer length, we know it's < DFLTPHYS */
652                 mapinfo->bp[i]->b_bufsize = lengths[i];
653 
654                 /* set the direction */
655                 mapinfo->bp[i]->b_iocmd = flags[i];
656 
657                 /*
658                  * Map the buffer into kernel memory.
659                  *
660                  * Note that useracc() alone is not a  sufficient test.
661                  * vmapbuf() can still fail due to a smaller file mapped
662                  * into a larger area of VM, or if userland races against
663                  * vmapbuf() after the useracc() check.
664                  */
665                 if (vmapbuf(mapinfo->bp[i]) < 0) {
666                         for (j = 0; j < i; ++j) {
667                                 *data_ptrs[j] = mapinfo->bp[j]->b_saveaddr;
668                                 vunmapbuf(mapinfo->bp[j]);
669                                 relpbuf(mapinfo->bp[j], NULL);
670                         }
671                         relpbuf(mapinfo->bp[i], NULL);
672                         PRELE(curproc);
673                         return(EACCES);
674                 }
675 
676                 /* set our pointer to the new mapped area */
677                 *data_ptrs[i] = mapinfo->bp[i]->b_data;
678 
679                 mapinfo->num_bufs_used++;
680         }
681 
682         /*
683          * Now that we've gotten this far, change ownership to the kernel
684          * of the buffers so that we don't run afoul of returning to user
685          * space with locks (on the buffer) held.
686          */
687         for (i = 0; i < numbufs; i++) {
688                 BUF_KERNPROC(mapinfo->bp[i]);
689         }
690 
691 
692         return(0);
693 }
694 
695 /*
696  * Unmap memory segments mapped into kernel virtual address space by
697  * cam_periph_mapmem().
698  */
699 void
700 cam_periph_unmapmem(union ccb *ccb, struct cam_periph_map_info *mapinfo)
701 {
702         int numbufs, i;
703         u_int8_t **data_ptrs[CAM_PERIPH_MAXMAPS];
704 
705         if (mapinfo->num_bufs_used <= 0) {
706                 /* allow ourselves to be swapped once again */
707                 PRELE(curproc);
708                 return;
709         }
710 
711         switch (ccb->ccb_h.func_code) {
712         case XPT_DEV_MATCH:
713                 numbufs = min(mapinfo->num_bufs_used, 2);
714 
715                 if (numbufs == 1) {
716                         data_ptrs[0] = (u_int8_t **)&ccb->cdm.matches;
717                 } else {
718                         data_ptrs[0] = (u_int8_t **)&ccb->cdm.patterns;
719                         data_ptrs[1] = (u_int8_t **)&ccb->cdm.matches;
720                 }
721                 break;
722         case XPT_SCSI_IO:
723         case XPT_CONT_TARGET_IO:
724                 data_ptrs[0] = &ccb->csio.data_ptr;
725                 numbufs = min(mapinfo->num_bufs_used, 1);
726                 break;
727         default:
728                 /* allow ourselves to be swapped once again */
729                 PRELE(curproc);
730                 return;
731                 break; /* NOTREACHED */ 
732         }
733 
734         for (i = 0; i < numbufs; i++) {
735                 /* Set the user's pointer back to the original value */
736                 *data_ptrs[i] = mapinfo->bp[i]->b_saveaddr;
737 
738                 /* unmap the buffer */
739                 vunmapbuf(mapinfo->bp[i]);
740 
741                 /* release the buffer */
742                 relpbuf(mapinfo->bp[i], NULL);
743         }
744 
745         /* allow ourselves to be swapped once again */
746         PRELE(curproc);
747 }
748 
749 union ccb *
750 cam_periph_getccb(struct cam_periph *periph, u_int32_t priority)
751 {
752         struct ccb_hdr *ccb_h;
753         struct mtx *mtx;
754 
755         mtx_assert(periph->sim->mtx, MA_OWNED);
756         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdgetccb\n"));
757 
758         while (SLIST_FIRST(&periph->ccb_list) == NULL) {
759                 if (periph->immediate_priority > priority)
760                         periph->immediate_priority = priority;
761                 xpt_schedule(periph, priority);
762                 if ((SLIST_FIRST(&periph->ccb_list) != NULL)
763                  && (SLIST_FIRST(&periph->ccb_list)->pinfo.priority == priority))
764                         break;
765                 mtx_assert(periph->sim->mtx, MA_OWNED);
766                 if (periph->sim->mtx == &Giant)
767                         mtx = NULL;
768                 else
769                         mtx = periph->sim->mtx;
770                 msleep(&periph->ccb_list, mtx, PRIBIO, "cgticb", 0);
771         }
772 
773         ccb_h = SLIST_FIRST(&periph->ccb_list);
774         SLIST_REMOVE_HEAD(&periph->ccb_list, periph_links.sle);
775         return ((union ccb *)ccb_h);
776 }
777 
778 void
779 cam_periph_ccbwait(union ccb *ccb)
780 {
781         struct mtx *mtx;
782         struct cam_sim *sim;
783 
784         sim = xpt_path_sim(ccb->ccb_h.path);
785         if (sim->mtx == &Giant)
786                 mtx = NULL;
787         else
788                 mtx = sim->mtx;
789         if ((ccb->ccb_h.pinfo.index != CAM_UNQUEUED_INDEX)
790          || ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG))
791                 msleep(&ccb->ccb_h.cbfcnp, mtx, PRIBIO, "cbwait", 0);
792 }
793 
794 int
795 cam_periph_ioctl(struct cam_periph *periph, int cmd, caddr_t addr,
796                  int (*error_routine)(union ccb *ccb, 
797                                       cam_flags camflags,
798                                       u_int32_t sense_flags))
799 {
800         union ccb            *ccb;
801         int                  error;
802         int                  found;
803 
804         error = found = 0;
805 
806         switch(cmd){
807         case CAMGETPASSTHRU:
808                 ccb = cam_periph_getccb(periph, /* priority */ 1);
809                 xpt_setup_ccb(&ccb->ccb_h,
810                               ccb->ccb_h.path,
811                               /*priority*/1);
812                 ccb->ccb_h.func_code = XPT_GDEVLIST;
813 
814                 /*
815                  * Basically, the point of this is that we go through
816                  * getting the list of devices, until we find a passthrough
817                  * device.  In the current version of the CAM code, the
818                  * only way to determine what type of device we're dealing
819                  * with is by its name.
820                  */
821                 while (found == 0) {
822                         ccb->cgdl.index = 0;
823                         ccb->cgdl.status = CAM_GDEVLIST_MORE_DEVS;
824                         while (ccb->cgdl.status == CAM_GDEVLIST_MORE_DEVS) {
825 
826                                 /* we want the next device in the list */
827                                 xpt_action(ccb);
828                                 if (strncmp(ccb->cgdl.periph_name, 
829                                     "pass", 4) == 0){
830                                         found = 1;
831                                         break;
832                                 }
833                         }
834                         if ((ccb->cgdl.status == CAM_GDEVLIST_LAST_DEVICE) &&
835                             (found == 0)) {
836                                 ccb->cgdl.periph_name[0] = '\0';
837                                 ccb->cgdl.unit_number = 0;
838                                 break;
839                         }
840                 }
841 
842                 /* copy the result back out */  
843                 bcopy(ccb, addr, sizeof(union ccb));
844 
845                 /* and release the ccb */
846                 xpt_release_ccb(ccb);
847 
848                 break;
849         default:
850                 error = ENOTTY;
851                 break;
852         }
853         return(error);
854 }
855 
856 int
857 cam_periph_runccb(union ccb *ccb,
858                   int (*error_routine)(union ccb *ccb,
859                                        cam_flags camflags,
860                                        u_int32_t sense_flags),
861                   cam_flags camflags, u_int32_t sense_flags,
862                   struct devstat *ds)
863 {
864         struct cam_sim *sim;
865         int error;
866  
867         error = 0;
868         sim = xpt_path_sim(ccb->ccb_h.path);
869         mtx_assert(sim->mtx, MA_OWNED);
870 
871         /*
872          * If the user has supplied a stats structure, and if we understand
873          * this particular type of ccb, record the transaction start.
874          */
875         if ((ds != NULL) && (ccb->ccb_h.func_code == XPT_SCSI_IO))
876                 devstat_start_transaction(ds, NULL);
877 
878         xpt_action(ccb);
879  
880         do {
881                 cam_periph_ccbwait(ccb);
882                 if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
883                         error = 0;
884                 else if (error_routine != NULL)
885                         error = (*error_routine)(ccb, camflags, sense_flags);
886                 else
887                         error = 0;
888 
889         } while (error == ERESTART);
890           
891         if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 
892                 cam_release_devq(ccb->ccb_h.path,
893                                  /* relsim_flags */0,
894                                  /* openings */0,
895                                  /* timeout */0,
896                                  /* getcount_only */ FALSE);
897 
898         if ((ds != NULL) && (ccb->ccb_h.func_code == XPT_SCSI_IO))
899                 devstat_end_transaction(ds,
900                                         ccb->csio.dxfer_len,
901                                         ccb->csio.tag_action & 0xf,
902                                         ((ccb->ccb_h.flags & CAM_DIR_MASK) ==
903                                         CAM_DIR_NONE) ?  DEVSTAT_NO_DATA : 
904                                         (ccb->ccb_h.flags & CAM_DIR_OUT) ?
905                                         DEVSTAT_WRITE : 
906                                         DEVSTAT_READ, NULL, NULL);
907 
908         return(error);
909 }
910 
911 void
912 cam_freeze_devq(struct cam_path *path)
913 {
914         struct ccb_hdr ccb_h;
915 
916         xpt_setup_ccb(&ccb_h,