FreeBSD/Linux Kernel Cross Reference
sys/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
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, |