File:
[DragonFly] /
src /
sys /
bus /
cam /
scsi /
scsi_pass.c
Revision
1.11:
download - view:
text,
annotated -
select for diffs
Thu May 13 23:49:11 2004 UTC (9 years ago) by
dillon
Branches:
MAIN
CVS tags:
HEAD
device switch 1/many: Remove d_autoq, add d_clone (where d_autoq was).
d_autoq was used to allow the device port dispatch to mix old-style synchronous
calls with new style messaging calls within a particular device. It was never
used for that purpose.
d_clone will be more fully implemented as work continues. We are going to
install d_port in the dev_t (struct specinfo) structure itself and d_clone
will be needed to allow devices to 'revector' the port on a minor-number
by minor-number basis, in particular allowing minor numbers to be directly
dispatched to distinct threads. This is something we will be needing later
on.
1: /*
2: * Copyright (c) 1997, 1998 Justin T. Gibbs.
3: * Copyright (c) 1997, 1998, 1999 Kenneth D. Merry.
4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions, and the following disclaimer,
11: * without modification, immediately at the beginning of the file.
12: * 2. The name of the author may not be used to endorse or promote products
13: * derived from this software without specific prior written permission.
14: *
15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
19: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25: * SUCH DAMAGE.
26: *
27: * $FreeBSD: src/sys/cam/scsi/scsi_pass.c,v 1.19 2000/01/17 06:27:37 mjacob Exp $
28: * $DragonFly: src/sys/bus/cam/scsi/scsi_pass.c,v 1.11 2004/05/13 23:49:11 dillon Exp $
29: */
30:
31: #include <sys/param.h>
32: #include <sys/systm.h>
33: #include <sys/kernel.h>
34: #include <sys/types.h>
35: #include <sys/buf.h>
36: #include <sys/malloc.h>
37: #include <sys/fcntl.h>
38: #include <sys/stat.h>
39: #include <sys/conf.h>
40: #include <sys/buf.h>
41: #include <sys/proc.h>
42: #include <sys/errno.h>
43: #include <sys/devicestat.h>
44: #include <sys/proc.h>
45: #include <sys/buf2.h>
46:
47: #include "../cam.h"
48: #include "../cam_ccb.h"
49: #include "../cam_extend.h"
50: #include "../cam_periph.h"
51: #include "../cam_xpt_periph.h"
52: #include "../cam_debug.h"
53:
54: #include "scsi_all.h"
55: #include "scsi_message.h"
56: #include "scsi_da.h"
57: #include "scsi_pass.h"
58:
59: typedef enum {
60: PASS_FLAG_OPEN = 0x01,
61: PASS_FLAG_LOCKED = 0x02,
62: PASS_FLAG_INVALID = 0x04
63: } pass_flags;
64:
65: typedef enum {
66: PASS_STATE_NORMAL
67: } pass_state;
68:
69: typedef enum {
70: PASS_CCB_BUFFER_IO,
71: PASS_CCB_WAITING
72: } pass_ccb_types;
73:
74: #define ccb_type ppriv_field0
75: #define ccb_bp ppriv_ptr1
76:
77: struct pass_softc {
78: pass_state state;
79: pass_flags flags;
80: u_int8_t pd_type;
81: struct buf_queue_head buf_queue;
82: union ccb saved_ccb;
83: struct devstat device_stats;
84: dev_t dev;
85: };
86:
87: #define PASS_CDEV_MAJOR 31
88:
89: static d_open_t passopen;
90: static d_close_t passclose;
91: static d_ioctl_t passioctl;
92: static d_strategy_t passstrategy;
93:
94: static periph_init_t passinit;
95: static periph_ctor_t passregister;
96: static periph_oninv_t passoninvalidate;
97: static periph_dtor_t passcleanup;
98: static periph_start_t passstart;
99: static void passasync(void *callback_arg, u_int32_t code,
100: struct cam_path *path, void *arg);
101: static void passdone(struct cam_periph *periph,
102: union ccb *done_ccb);
103: static int passerror(union ccb *ccb, u_int32_t cam_flags,
104: u_int32_t sense_flags);
105: static int passsendccb(struct cam_periph *periph, union ccb *ccb,
106: union ccb *inccb);
107:
108: static struct periph_driver passdriver =
109: {
110: passinit, "pass",
111: TAILQ_HEAD_INITIALIZER(passdriver.units), /* generation */ 0
112: };
113:
114: DATA_SET(periphdriver_set, passdriver);
115:
116: static struct cdevsw pass_cdevsw = {
117: /* name */ "pass",
118: /* maj */ PASS_CDEV_MAJOR,
119: /* flags */ 0,
120: /* port */ NULL,
121: /* clone */ NULL,
122:
123: /* open */ passopen,
124: /* close */ passclose,
125: /* read */ physread,
126: /* write */ physwrite,
127: /* ioctl */ passioctl,
128: /* poll */ nopoll,
129: /* mmap */ nommap,
130: /* strategy */ passstrategy,
131: /* dump */ nodump,
132: /* psize */ nopsize
133: };
134:
135: static struct extend_array *passperiphs;
136:
137: static void
138: passinit(void)
139: {
140: cam_status status;
141: struct cam_path *path;
142:
143: /*
144: * Create our extend array for storing the devices we attach to.
145: */
146: passperiphs = cam_extend_new();
147: if (passperiphs == NULL) {
148: printf("passm: Failed to alloc extend array!\n");
149: return;
150: }
151:
152: /*
153: * Install a global async callback. This callback will
154: * receive async callbacks like "new device found".
155: */
156: status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
157: CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
158:
159: if (status == CAM_REQ_CMP) {
160: struct ccb_setasync csa;
161:
162: xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
163: csa.ccb_h.func_code = XPT_SASYNC_CB;
164: csa.event_enable = AC_FOUND_DEVICE;
165: csa.callback = passasync;
166: csa.callback_arg = NULL;
167: xpt_action((union ccb *)&csa);
168: status = csa.ccb_h.status;
169: xpt_free_path(path);
170: }
171:
172: if (status != CAM_REQ_CMP) {
173: printf("pass: Failed to attach master async callback "
174: "due to status 0x%x!\n", status);
175: }
176:
177: }
178:
179: static void
180: passoninvalidate(struct cam_periph *periph)
181: {
182: int s;
183: struct pass_softc *softc;
184: struct buf *q_bp;
185: struct ccb_setasync csa;
186:
187: softc = (struct pass_softc *)periph->softc;
188:
189: /*
190: * De-register any async callbacks.
191: */
192: xpt_setup_ccb(&csa.ccb_h, periph->path,
193: /* priority */ 5);
194: csa.ccb_h.func_code = XPT_SASYNC_CB;
195: csa.event_enable = 0;
196: csa.callback = passasync;
197: csa.callback_arg = periph;
198: xpt_action((union ccb *)&csa);
199:
200: softc->flags |= PASS_FLAG_INVALID;
201:
202: /*
203: * Although the oninvalidate() routines are always called at
204: * splsoftcam, we need to be at splbio() here to keep the buffer
205: * queue from being modified while we traverse it.
206: */
207: s = splbio();
208:
209: /*
210: * Return all queued I/O with ENXIO.
211: * XXX Handle any transactions queued to the card
212: * with XPT_ABORT_CCB.
213: */
214: while ((q_bp = bufq_first(&softc->buf_queue)) != NULL){
215: bufq_remove(&softc->buf_queue, q_bp);
216: q_bp->b_resid = q_bp->b_bcount;
217: q_bp->b_error = ENXIO;
218: q_bp->b_flags |= B_ERROR;
219: biodone(q_bp);
220: }
221: splx(s);
222:
223: if (bootverbose) {
224: xpt_print_path(periph->path);
225: printf("lost device\n");
226: }
227:
228: }
229:
230: static void
231: passcleanup(struct cam_periph *periph)
232: {
233: struct pass_softc *softc;
234:
235: softc = (struct pass_softc *)periph->softc;
236:
237: devstat_remove_entry(&softc->device_stats);
238:
239: destroy_dev(softc->dev);
240:
241: cam_extend_release(passperiphs, periph->unit_number);
242:
243: if (bootverbose) {
244: xpt_print_path(periph->path);
245: printf("removing device entry\n");
246: }
247: free(softc, M_DEVBUF);
248: }
249:
250: static void
251: passasync(void *callback_arg, u_int32_t code,
252: struct cam_path *path, void *arg)
253: {
254: struct cam_periph *periph;
255:
256: periph = (struct cam_periph *)callback_arg;
257:
258: switch (code) {
259: case AC_FOUND_DEVICE:
260: {
261: struct ccb_getdev *cgd;
262: cam_status status;
263:
264: cgd = (struct ccb_getdev *)arg;
265:
266: /*
267: * Allocate a peripheral instance for
268: * this device and start the probe
269: * process.
270: */
271: status = cam_periph_alloc(passregister, passoninvalidate,
272: passcleanup, passstart, "pass",
273: CAM_PERIPH_BIO, cgd->ccb_h.path,
274: passasync, AC_FOUND_DEVICE, cgd);
275:
276: if (status != CAM_REQ_CMP
277: && status != CAM_REQ_INPROG)
278: printf("passasync: Unable to attach new device "
279: "due to status 0x%x\n", status);
280:
281: break;
282: }
283: default:
284: cam_periph_async(periph, code, path, arg);
285: break;
286: }
287: }
288:
289: static cam_status
290: passregister(struct cam_periph *periph, void *arg)
291: {
292: struct pass_softc *softc;
293: struct ccb_setasync csa;
294: struct ccb_getdev *cgd;
295:
296: cgd = (struct ccb_getdev *)arg;
297: if (periph == NULL) {
298: printf("passregister: periph was NULL!!\n");
299: return(CAM_REQ_CMP_ERR);
300: }
301:
302: if (cgd == NULL) {
303: printf("passregister: no getdev CCB, can't register device\n");
304: return(CAM_REQ_CMP_ERR);
305: }
306:
307: softc = malloc(sizeof(*softc), M_DEVBUF, M_INTWAIT | M_ZERO);
308: softc->state = PASS_STATE_NORMAL;
309: softc->pd_type = SID_TYPE(&cgd->inq_data);
310: bufq_init(&softc->buf_queue);
311:
312: periph->softc = softc;
313:
314: cam_extend_set(passperiphs, periph->unit_number, periph);
315: /*
316: * We pass in 0 for a blocksize, since we don't
317: * know what the blocksize of this device is, if
318: * it even has a blocksize.
319: */
320: devstat_add_entry(&softc->device_stats, "pass", periph->unit_number,
321: 0, DEVSTAT_NO_BLOCKSIZE | DEVSTAT_NO_ORDERED_TAGS,
322: softc->pd_type |
323: DEVSTAT_TYPE_IF_SCSI |
324: DEVSTAT_TYPE_PASS,
325: DEVSTAT_PRIORITY_PASS);
326:
327: /* Register the device */
328: softc->dev = make_dev(&pass_cdevsw, periph->unit_number, UID_ROOT,
329: GID_OPERATOR, 0600, "%s%d", periph->periph_name,
330: periph->unit_number);
331:
332: /*
333: * Add an async callback so that we get
334: * notified if this device goes away.
335: */
336: xpt_setup_ccb(&csa.ccb_h, periph->path, /* priority */ 5);
337: csa.ccb_h.func_code = XPT_SASYNC_CB;
338: csa.event_enable = AC_LOST_DEVICE;
339: csa.callback = passasync;
340: csa.callback_arg = periph;
341: xpt_action((union ccb *)&csa);
342:
343: if (bootverbose)
344: xpt_announce_periph(periph, NULL);
345:
346: return(CAM_REQ_CMP);
347: }
348:
349: static int
350: passopen(dev_t dev, int flags, int fmt, struct thread *td)
351: {
352: struct cam_periph *periph;
353: struct pass_softc *softc;
354: int unit, error;
355: int s;
356:
357: error = 0; /* default to no error */
358:
359: /* unit = dkunit(dev); */
360: /* XXX KDM fix this */
361: unit = minor(dev) & 0xff;
362:
363: periph = cam_extend_get(passperiphs, unit);
364:
365: if (periph == NULL)
366: return (ENXIO);
367:
368: softc = (struct pass_softc *)periph->softc;
369:
370: s = splsoftcam();
371: if (softc->flags & PASS_FLAG_INVALID) {
372: splx(s);
373: return(ENXIO);
374: }
375:
376: /*
377: * Don't allow access when we're running at a high securelvel.
378: */
379: if (securelevel > 1) {
380: splx(s);
381: return(EPERM);
382: }
383:
384: /*
385: * Only allow read-write access.
386: */
387: if (((flags & FWRITE) == 0) || ((flags & FREAD) == 0)) {
388: splx(s);
389: return(EPERM);
390: }
391:
392: /*
393: * We don't allow nonblocking access.
394: */
395: if ((flags & O_NONBLOCK) != 0) {
396: xpt_print_path(periph->path);
397: printf("can't do nonblocking accesss\n");
398: splx(s);
399: return(EINVAL);
400: }
401:
402: if ((error = cam_periph_lock(periph, PCATCH)) != 0) {
403: splx(s);
404: return (error);
405: }
406:
407: splx(s);
408:
409: if ((softc->flags & PASS_FLAG_OPEN) == 0) {
410: if (cam_periph_acquire(periph) != CAM_REQ_CMP)
411: return(ENXIO);
412: softc->flags |= PASS_FLAG_OPEN;
413: }
414:
415: cam_periph_unlock(periph);
416:
417: return (error);
418: }
419:
420: static int
421: passclose(dev_t dev, int flag, int fmt, struct thread *td)
422: {
423: struct cam_periph *periph;
424: struct pass_softc *softc;
425: int unit, error;
426:
427: /* unit = dkunit(dev); */
428: /* XXX KDM fix this */
429: unit = minor(dev) & 0xff;
430:
431: periph = cam_extend_get(passperiphs, unit);
432: if (periph == NULL)
433: return (ENXIO);
434:
435: softc = (struct pass_softc *)periph->softc;
436:
437: if ((error = cam_periph_lock(periph, 0)) != 0)
438: return (error);
439:
440: softc->flags &= ~PASS_FLAG_OPEN;
441:
442: cam_periph_unlock(periph);
443: cam_periph_release(periph);
444:
445: return (0);
446: }
447:
448: /*
449: * Actually translate the requested transfer into one the physical driver
450: * can understand. The transfer is described by a buf and will include
451: * only one physical transfer.
452: */
453: static void
454: passstrategy(struct buf *bp)
455: {
456: struct cam_periph *periph;
457: struct pass_softc *softc;
458: u_int unit;
459: int s;
460:
461: /*
462: * The read/write interface for the passthrough driver doesn't
463: * really work right now. So, we just pass back EINVAL to tell the
464: * user to go away.
465: */
466: bp->b_error = EINVAL;
467: goto bad;
468:
469: /* unit = dkunit(bp->b_dev); */
470: /* XXX KDM fix this */
471: unit = minor(bp->b_dev) & 0xff;
472:
473: periph = cam_extend_get(passperiphs, unit);
474: if (periph == NULL) {
475: bp->b_error = ENXIO;
476: goto bad;
477: }
478: softc = (struct pass_softc *)periph->softc;
479:
480: /*
481: * Odd number of bytes or negative offset
482: */
483: /* valid request? */
484: if (bp->b_blkno < 0) {
485: bp->b_error = EINVAL;
486: goto bad;
487: }
488:
489: /*
490: * Mask interrupts so that the pack cannot be invalidated until
491: * after we are in the queue. Otherwise, we might not properly
492: * clean up one of the buffers.
493: */
494: s = splbio();
495:
496: bufq_insert_tail(&softc->buf_queue, bp);
497:
498: splx(s);
499:
500: /*
501: * Schedule ourselves for performing the work.
502: */
503: xpt_schedule(periph, /* XXX priority */1);
504:
505: return;
506: bad:
507: bp->b_flags |= B_ERROR;
508:
509: /*
510: * Correctly set the buf to indicate a completed xfer
511: */
512: bp->b_resid = bp->b_bcount;
513: biodone(bp);
514: return;
515: }
516:
517: static void
518: passstart(struct cam_periph *periph, union ccb *start_ccb)
519: {
520: struct pass_softc *softc;
521: int s;
522:
523: softc = (struct pass_softc *)periph->softc;
524:
525: switch (softc->state) {
526: case PASS_STATE_NORMAL:
527: {
528: struct buf *bp;
529:
530: s = splbio();
531: bp = bufq_first(&softc->buf_queue);
532: if (periph->immediate_priority <= periph->pinfo.priority) {
533: start_ccb->ccb_h.ccb_type = PASS_CCB_WAITING;
534: SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
535: periph_links.sle);
536: periph->immediate_priority = CAM_PRIORITY_NONE;
537: splx(s);
538: wakeup(&periph->ccb_list);
539: } else if (bp == NULL) {
540: splx(s);
541: xpt_release_ccb(start_ccb);
542: } else {
543:
544: bufq_remove(&softc->buf_queue, bp);
545:
546: devstat_start_transaction(&softc->device_stats);
547:
548: /*
549: * XXX JGibbs -
550: * Interpret the contents of the bp as a CCB
551: * and pass it to a routine shared by our ioctl
552: * code and passtart.
553: * For now, just biodone it with EIO so we don't
554: * hang.
555: */
556: bp->b_error = EIO;
557: bp->b_flags |= B_ERROR;
558: bp->b_resid = bp->b_bcount;
559: biodone(bp);
560: bp = bufq_first(&softc->buf_queue);
561: splx(s);
562:
563: xpt_action(start_ccb);
564:
565: }
566: if (bp != NULL) {
567: /* Have more work to do, so ensure we stay scheduled */
568: xpt_schedule(periph, /* XXX priority */1);
569: }
570: break;
571: }
572: }
573: }
574: static void
575: passdone(struct cam_periph *periph, union ccb *done_ccb)
576: {
577: struct pass_softc *softc;
578: struct ccb_scsiio *csio;
579:
580: softc = (struct pass_softc *)periph->softc;
581: csio = &done_ccb->csio;
582: switch (csio->ccb_h.ccb_type) {
583: case PASS_CCB_BUFFER_IO:
584: {
585: struct buf *bp;
586: cam_status status;
587: u_int8_t scsi_status;
588: devstat_trans_flags ds_flags;
589:
590: status = done_ccb->ccb_h.status;
591: scsi_status = done_ccb->csio.scsi_status;
592: bp = (struct buf *)done_ccb->ccb_h.ccb_bp;
593: /* XXX handle errors */
594: if (!(((status & CAM_STATUS_MASK) == CAM_REQ_CMP)
595: && (scsi_status == SCSI_STATUS_OK))) {
596: int error;
597:
598: if ((error = passerror(done_ccb, 0, 0)) == ERESTART) {
599: /*
600: * A retry was scheuled, so
601: * just return.
602: */
603: return;
604: }
605:
606: /*
607: * XXX unfreeze the queue after we complete
608: * the abort process
609: */
610: bp->b_error = error;
611: bp->b_flags |= B_ERROR;
612: }
613:
614: if ((done_ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
615: ds_flags = DEVSTAT_READ;
616: else if ((done_ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
617: ds_flags = DEVSTAT_WRITE;
618: else
619: ds_flags = DEVSTAT_NO_DATA;
620:
621: devstat_end_transaction_buf(&softc->device_stats, bp);
622: biodone(bp);
623: break;
624: }
625: case PASS_CCB_WAITING:
626: {
627: /* Caller will release the CCB */
628: wakeup(&done_ccb->ccb_h.cbfcnp);
629: return;
630: }
631: }
632: xpt_release_ccb(done_ccb);
633: }
634:
635: static int
636: passioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
637: {
638: struct cam_periph *periph;
639: struct pass_softc *softc;
640: u_int8_t unit;
641: int error;
642:
643:
644: /* unit = dkunit(dev); */
645: /* XXX KDM fix this */
646: unit = minor(dev) & 0xff;
647:
648: periph = cam_extend_get(passperiphs, unit);
649:
650: if (periph == NULL)
651: return(ENXIO);
652:
653: softc = (struct pass_softc *)periph->softc;
654:
655: error = 0;
656:
657: switch (cmd) {
658:
659: case CAMIOCOMMAND:
660: {
661: union ccb *inccb;
662: union ccb *ccb;
663: int ccb_malloced;
664:
665: inccb = (union ccb *)addr;
666:
667: /*
668: * Some CCB types, like scan bus and scan lun can only go
669: * through the transport layer device.
670: */
671: if (inccb->ccb_h.func_code & XPT_FC_XPT_ONLY) {
672: xpt_print_path(periph->path);
673: printf("CCB function code %#x is restricted to the "
674: "XPT device\n", inccb->ccb_h.func_code);
675: error = ENODEV;
676: break;
677: }
678:
679: /*
680: * Non-immediate CCBs need a CCB from the per-device pool
681: * of CCBs, which is scheduled by the transport layer.
682: * Immediate CCBs and user-supplied CCBs should just be
683: * malloced.
684: */
685: if ((inccb->ccb_h.func_code & XPT_FC_QUEUED)
686: && ((inccb->ccb_h.func_code & XPT_FC_USER_CCB) == 0)) {
687: ccb = cam_periph_getccb(periph,
688: inccb->ccb_h.pinfo.priority);
689: ccb_malloced = 0;
690: } else {
691: ccb = xpt_alloc_ccb();
692:
693: if (ccb != NULL)
694: xpt_setup_ccb(&ccb->ccb_h, periph->path,
695: inccb->ccb_h.pinfo.priority);
696: ccb_malloced = 1;
697: }
698:
699: if (ccb == NULL) {
700: xpt_print_path(periph->path);
701: printf("unable to allocate CCB\n");
702: error = ENOMEM;
703: break;
704: }
705:
706: error = passsendccb(periph, ccb, inccb);
707:
708: if (ccb_malloced)
709: xpt_free_ccb(ccb);
710: else
711: xpt_release_ccb(ccb);
712:
713: break;
714: }
715: default:
716: error = cam_periph_ioctl(periph, cmd, addr, passerror);
717: break;
718: }
719:
720: return(error);
721: }
722:
723: /*
724: * Generally, "ccb" should be the CCB supplied by the kernel. "inccb"
725: * should be the CCB that is copied in from the user.
726: */
727: static int
728: passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb)
729: {
730: struct pass_softc *softc;
731: struct cam_periph_map_info mapinfo;
732: int error, need_unmap;
733:
734: softc = (struct pass_softc *)periph->softc;
735:
736: need_unmap = 0;
737:
738: /*
739: * There are some fields in the CCB header that need to be
740: * preserved, the rest we get from the user.
741: */
742: xpt_merge_ccb(ccb, inccb);
743:
744: /*
745: * There's no way for the user to have a completion
746: * function, so we put our own completion function in here.
747: */
748: ccb->ccb_h.cbfcnp = passdone;
749:
750: /*
751: * We only attempt to map the user memory into kernel space
752: * if they haven't passed in a physical memory pointer,
753: * and if there is actually an I/O operation to perform.
754: * Right now cam_periph_mapmem() only supports SCSI and device
755: * match CCBs. For the SCSI CCBs, we only pass the CCB in if
756: * there's actually data to map. cam_periph_mapmem() will do the
757: * right thing, even if there isn't data to map, but since CCBs
758: * without data are a reasonably common occurance (e.g. test unit
759: * ready), it will save a few cycles if we check for it here.
760: */
761: if (((ccb->ccb_h.flags & CAM_DATA_PHYS) == 0)
762: && (((ccb->ccb_h.func_code == XPT_SCSI_IO)
763: && ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE))
764: || (ccb->ccb_h.func_code == XPT_DEV_MATCH))) {
765:
766: bzero(&mapinfo, sizeof(mapinfo));
767:
768: error = cam_periph_mapmem(ccb, &mapinfo);
769:
770: /*
771: * cam_periph_mapmem returned an error, we can't continue.
772: * Return the error to the user.
773: */
774: if (error)
775: return(error);
776:
777: /*
778: * We successfully mapped the memory in, so we need to
779: * unmap it when the transaction is done.
780: */
781: need_unmap = 1;
782: }
783:
784: /*
785: * If the user wants us to perform any error recovery, then honor
786: * that request. Otherwise, it's up to the user to perform any
787: * error recovery.
788: */
789: error = cam_periph_runccb(ccb,
790: (ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ?
791: passerror : NULL,
792: /* cam_flags */ 0,
793: /* sense_flags */SF_RETRY_UA | SF_RETRY_SELTO,
794: &softc->device_stats);
795:
796: if (need_unmap != 0)
797: cam_periph_unmapmem(ccb, &mapinfo);
798:
799: ccb->ccb_h.cbfcnp = NULL;
800: ccb->ccb_h.periph_priv = inccb->ccb_h.periph_priv;
801: bcopy(ccb, inccb, sizeof(union ccb));
802:
803: return(error);
804: }
805:
806: static int
807: passerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
808: {
809: struct cam_periph *periph;
810: struct pass_softc *softc;
811:
812: periph = xpt_path_periph(ccb->ccb_h.path);
813: softc = (struct pass_softc *)periph->softc;
814:
815: return(cam_periph_error(ccb, cam_flags, sense_flags,
816: &softc->saved_ccb));
817: }