2 * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs.
3 * Copyright (c) 1997, 1998, 1999 Kenneth D. Merry.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
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.26 2007/12/02 04:24:11 pavalos Exp $
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/types.h>
36 #include <sys/malloc.h>
37 #include <sys/fcntl.h>
40 #include <sys/errno.h>
41 #include <sys/devicestat.h>
43 #include <sys/thread2.h>
46 #include "../cam_ccb.h"
47 #include "../cam_extend.h"
48 #include "../cam_periph.h"
49 #include "../cam_queue.h"
50 #include "../cam_xpt_periph.h"
51 #include "../cam_debug.h"
54 #include "scsi_message.h"
56 #include "scsi_pass.h"
59 PASS_FLAG_OPEN
= 0x01,
60 PASS_FLAG_LOCKED
= 0x02,
61 PASS_FLAG_INVALID
= 0x04
73 #define ccb_type ppriv_field0
74 #define ccb_bio ppriv_ptr1
81 struct devstat device_stats
;
84 #define PASS_CDEV_MAJOR 31
86 static d_open_t passopen
;
87 static d_close_t passclose
;
88 static d_ioctl_t passioctl
;
90 static periph_init_t passinit
;
91 static periph_ctor_t passregister
;
92 static periph_oninv_t passoninvalidate
;
93 static periph_dtor_t passcleanup
;
94 static periph_start_t passstart
;
95 static void passasync(void *callback_arg
, u_int32_t code
,
96 struct cam_path
*path
, void *arg
);
97 static void passdone(struct cam_periph
*periph
,
99 static int passerror(union ccb
*ccb
, u_int32_t cam_flags
,
100 u_int32_t sense_flags
);
101 static int passsendccb(struct cam_periph
*periph
, union ccb
*ccb
,
104 static struct periph_driver passdriver
=
107 TAILQ_HEAD_INITIALIZER(passdriver
.units
), /* generation */ 0
110 PERIPHDRIVER_DECLARE(pass
, passdriver
);
112 static struct dev_ops pass_ops
= {
113 { "pass", PASS_CDEV_MAJOR
, 0 },
115 .d_close
= passclose
,
118 .d_ioctl
= passioctl
,
119 .d_strategy
= nostrategy
,
122 static struct extend_array
*passperiphs
;
128 struct cam_path
*path
;
131 * Create our extend array for storing the devices we attach to.
133 passperiphs
= cam_extend_new();
134 if (passperiphs
== NULL
) {
135 kprintf("passm: Failed to alloc extend array!\n");
140 * Install a global async callback. This callback will
141 * receive async callbacks like "new device found".
143 status
= xpt_create_path(&path
, /*periph*/NULL
, CAM_XPT_PATH_ID
,
144 CAM_TARGET_WILDCARD
, CAM_LUN_WILDCARD
);
146 if (status
== CAM_REQ_CMP
) {
147 struct ccb_setasync csa
;
149 xpt_setup_ccb(&csa
.ccb_h
, path
, /*priority*/5);
150 csa
.ccb_h
.func_code
= XPT_SASYNC_CB
;
151 csa
.event_enable
= AC_FOUND_DEVICE
;
152 csa
.callback
= passasync
;
153 csa
.callback_arg
= NULL
;
154 xpt_action((union ccb
*)&csa
);
155 status
= csa
.ccb_h
.status
;
159 if (status
!= CAM_REQ_CMP
) {
160 kprintf("pass: Failed to attach master async callback "
161 "due to status 0x%x!\n", status
);
167 passoninvalidate(struct cam_periph
*periph
)
169 struct pass_softc
*softc
;
170 struct ccb_setasync csa
;
172 softc
= (struct pass_softc
*)periph
->softc
;
175 * De-register any async callbacks.
177 xpt_setup_ccb(&csa
.ccb_h
, periph
->path
,
179 csa
.ccb_h
.func_code
= XPT_SASYNC_CB
;
180 csa
.event_enable
= 0;
181 csa
.callback
= passasync
;
182 csa
.callback_arg
= periph
;
183 xpt_action((union ccb
*)&csa
);
185 softc
->flags
|= PASS_FLAG_INVALID
;
188 xpt_print_path(periph
->path
);
189 kprintf("lost device\n");
195 passcleanup(struct cam_periph
*periph
)
197 struct pass_softc
*softc
;
199 softc
= (struct pass_softc
*)periph
->softc
;
201 devstat_remove_entry(&softc
->device_stats
);
203 cam_extend_release(passperiphs
, periph
->unit_number
);
206 xpt_print_path(periph
->path
);
207 kprintf("removing device entry\n");
209 dev_ops_remove(&pass_ops
, -1, periph
->unit_number
);
210 kfree(softc
, M_DEVBUF
);
214 passasync(void *callback_arg
, u_int32_t code
,
215 struct cam_path
*path
, void *arg
)
217 struct cam_periph
*periph
;
219 periph
= (struct cam_periph
*)callback_arg
;
222 case AC_FOUND_DEVICE
:
224 struct ccb_getdev
*cgd
;
227 cgd
= (struct ccb_getdev
*)arg
;
232 * Allocate a peripheral instance for
233 * this device and start the probe
236 status
= cam_periph_alloc(passregister
, passoninvalidate
,
237 passcleanup
, passstart
, "pass",
238 CAM_PERIPH_BIO
, cgd
->ccb_h
.path
,
239 passasync
, AC_FOUND_DEVICE
, cgd
);
241 if (status
!= CAM_REQ_CMP
242 && status
!= CAM_REQ_INPROG
) {
243 const struct cam_status_entry
*entry
;
245 entry
= cam_fetch_status_entry(status
);
247 kprintf("passasync: Unable to attach new device "
248 "due to status %#x: %s\n", status
, entry
?
249 entry
->status_text
: "Unknown");
255 cam_periph_async(periph
, code
, path
, arg
);
261 passregister(struct cam_periph
*periph
, void *arg
)
263 struct pass_softc
*softc
;
264 struct ccb_setasync csa
;
265 struct ccb_getdev
*cgd
;
268 cgd
= (struct ccb_getdev
*)arg
;
269 if (periph
== NULL
) {
270 kprintf("passregister: periph was NULL!!\n");
271 return(CAM_REQ_CMP_ERR
);
275 kprintf("passregister: no getdev CCB, can't register device\n");
276 return(CAM_REQ_CMP_ERR
);
279 softc
= kmalloc(sizeof(*softc
), M_DEVBUF
, M_INTWAIT
| M_ZERO
);
280 softc
->state
= PASS_STATE_NORMAL
;
281 softc
->pd_type
= SID_TYPE(&cgd
->inq_data
);
283 periph
->softc
= softc
;
284 cam_extend_set(passperiphs
, periph
->unit_number
, periph
);
287 * We pass in 0 for a blocksize, since we don't
288 * know what the blocksize of this device is, if
289 * it even has a blocksize.
291 no_tags
= (cgd
->inq_data
.flags
& SID_CmdQue
) == 0;
292 devstat_add_entry(&softc
->device_stats
, "pass", periph
->unit_number
, 0,
294 | (no_tags
? DEVSTAT_NO_ORDERED_TAGS
: 0),
296 DEVSTAT_TYPE_IF_SCSI
|
298 DEVSTAT_PRIORITY_PASS
);
300 /* Register the device */
301 dev_ops_add(&pass_ops
, -1, periph
->unit_number
);
302 make_dev(&pass_ops
, periph
->unit_number
, UID_ROOT
,
303 GID_OPERATOR
, 0600, "%s%d", periph
->periph_name
,
304 periph
->unit_number
);
307 * Add an async callback so that we get
308 * notified if this device goes away.
310 xpt_setup_ccb(&csa
.ccb_h
, periph
->path
, /* priority */ 5);
311 csa
.ccb_h
.func_code
= XPT_SASYNC_CB
;
312 csa
.event_enable
= AC_LOST_DEVICE
;
313 csa
.callback
= passasync
;
314 csa
.callback_arg
= periph
;
315 xpt_action((union ccb
*)&csa
);
318 xpt_announce_periph(periph
, NULL
);
324 passopen(struct dev_open_args
*ap
)
326 cdev_t dev
= ap
->a_head
.a_dev
;
327 struct cam_periph
*periph
;
328 struct pass_softc
*softc
;
331 error
= 0; /* default to no error */
333 /* unit = dkunit(dev); */
334 /* XXX KDM fix this */
335 unit
= minor(dev
) & 0xff;
337 periph
= cam_extend_get(passperiphs
, unit
);
342 softc
= (struct pass_softc
*)periph
->softc
;
345 if (softc
->flags
& PASS_FLAG_INVALID
) {
351 * Don't allow access when we're running at a high securelevel.
353 if (securelevel
> 1) {
359 * Only allow read-write access.
361 if (((ap
->a_oflags
& FWRITE
) == 0) || ((ap
->a_oflags
& FREAD
) == 0)) {
367 * We don't allow nonblocking access.
369 if ((ap
->a_oflags
& O_NONBLOCK
) != 0) {
370 xpt_print_path(periph
->path
);
371 kprintf("can't do nonblocking access\n");
376 if ((error
= cam_periph_lock(periph
, PCATCH
)) != 0) {
383 if ((softc
->flags
& PASS_FLAG_OPEN
) == 0) {
384 if (cam_periph_acquire(periph
) != CAM_REQ_CMP
)
386 softc
->flags
|= PASS_FLAG_OPEN
;
389 cam_periph_unlock(periph
);
395 passclose(struct dev_close_args
*ap
)
397 cdev_t dev
= ap
->a_head
.a_dev
;
398 struct cam_periph
*periph
;
399 struct pass_softc
*softc
;
402 /* unit = dkunit(dev); */
403 /* XXX KDM fix this */
404 unit
= minor(dev
) & 0xff;
406 periph
= cam_extend_get(passperiphs
, unit
);
410 softc
= (struct pass_softc
*)periph
->softc
;
412 if ((error
= cam_periph_lock(periph
, 0)) != 0)
415 softc
->flags
&= ~PASS_FLAG_OPEN
;
417 cam_periph_unlock(periph
);
418 cam_periph_release(periph
);
424 passstart(struct cam_periph
*periph
, union ccb
*start_ccb
)
426 struct pass_softc
*softc
;
428 softc
= (struct pass_softc
*)periph
->softc
;
430 switch (softc
->state
) {
431 case PASS_STATE_NORMAL
:
433 start_ccb
->ccb_h
.ccb_type
= PASS_CCB_WAITING
;
434 SLIST_INSERT_HEAD(&periph
->ccb_list
, &start_ccb
->ccb_h
,
436 periph
->immediate_priority
= CAM_PRIORITY_NONE
;
438 wakeup(&periph
->ccb_list
);
444 passdone(struct cam_periph
*periph
, union ccb
*done_ccb
)
446 struct pass_softc
*softc
;
447 struct ccb_scsiio
*csio
;
449 softc
= (struct pass_softc
*)periph
->softc
;
450 csio
= &done_ccb
->csio
;
451 switch (csio
->ccb_h
.ccb_type
) {
452 case PASS_CCB_WAITING
:
453 /* Caller will release the CCB */
454 wakeup(&done_ccb
->ccb_h
.cbfcnp
);
457 xpt_release_ccb(done_ccb
);
461 passioctl(struct dev_ioctl_args
*ap
)
463 cdev_t dev
= ap
->a_head
.a_dev
;
464 caddr_t addr
= ap
->a_data
;
465 struct cam_periph
*periph
;
466 struct pass_softc
*softc
;
471 /* unit = dkunit(dev); */
472 /* XXX KDM fix this */
473 unit
= minor(dev
) & 0xff;
475 periph
= cam_extend_get(passperiphs
, unit
);
480 softc
= (struct pass_softc
*)periph
->softc
;
492 inccb
= (union ccb
*)addr
;
495 * Some CCB types, like scan bus and scan lun can only go
496 * through the transport layer device.
498 if (inccb
->ccb_h
.func_code
& XPT_FC_XPT_ONLY
) {
499 xpt_print_path(periph
->path
);
500 kprintf("CCB function code %#x is restricted to the "
501 "XPT device\n", inccb
->ccb_h
.func_code
);
507 * Non-immediate CCBs need a CCB from the per-device pool
508 * of CCBs, which is scheduled by the transport layer.
509 * Immediate CCBs and user-supplied CCBs should just be
512 if ((inccb
->ccb_h
.func_code
& XPT_FC_QUEUED
)
513 && ((inccb
->ccb_h
.func_code
& XPT_FC_USER_CCB
) == 0)) {
514 ccb
= cam_periph_getccb(periph
,
515 inccb
->ccb_h
.pinfo
.priority
);
518 ccb
= xpt_alloc_ccb();
521 xpt_setup_ccb(&ccb
->ccb_h
, periph
->path
,
522 inccb
->ccb_h
.pinfo
.priority
);
527 xpt_print_path(periph
->path
);
528 kprintf("unable to allocate CCB\n");
533 error
= passsendccb(periph
, ccb
, inccb
);
538 xpt_release_ccb(ccb
);
543 error
= cam_periph_ioctl(periph
, ap
->a_cmd
, addr
, passerror
);
551 * Generally, "ccb" should be the CCB supplied by the kernel. "inccb"
552 * should be the CCB that is copied in from the user.
555 passsendccb(struct cam_periph
*periph
, union ccb
*ccb
, union ccb
*inccb
)
557 struct pass_softc
*softc
;
558 struct cam_periph_map_info mapinfo
;
559 int error
, need_unmap
;
561 softc
= (struct pass_softc
*)periph
->softc
;
566 * There are some fields in the CCB header that need to be
567 * preserved, the rest we get from the user.
569 xpt_merge_ccb(ccb
, inccb
);
572 * There's no way for the user to have a completion
573 * function, so we put our own completion function in here.
575 ccb
->ccb_h
.cbfcnp
= passdone
;
578 * We only attempt to map the user memory into kernel space
579 * if they haven't passed in a physical memory pointer,
580 * and if there is actually an I/O operation to perform.
581 * Right now cam_periph_mapmem() only supports SCSI and device
582 * match CCBs. For the SCSI CCBs, we only pass the CCB in if
583 * there's actually data to map. cam_periph_mapmem() will do the
584 * right thing, even if there isn't data to map, but since CCBs
585 * without data are a reasonably common occurance (e.g. test unit
586 * ready), it will save a few cycles if we check for it here.
588 if (((ccb
->ccb_h
.flags
& CAM_DATA_PHYS
) == 0)
589 && (((ccb
->ccb_h
.func_code
== XPT_SCSI_IO
)
590 && ((ccb
->ccb_h
.flags
& CAM_DIR_MASK
) != CAM_DIR_NONE
))
591 || (ccb
->ccb_h
.func_code
== XPT_DEV_MATCH
))) {
593 bzero(&mapinfo
, sizeof(mapinfo
));
595 error
= cam_periph_mapmem(ccb
, &mapinfo
);
598 * cam_periph_mapmem returned an error, we can't continue.
599 * Return the error to the user.
605 * We successfully mapped the memory in, so we need to
606 * unmap it when the transaction is done.
612 * If the user wants us to perform any error recovery, then honor
613 * that request. Otherwise, it's up to the user to perform any
616 error
= cam_periph_runccb(ccb
,
617 (ccb
->ccb_h
.flags
& CAM_PASS_ERR_RECOVER
) ?
619 /* cam_flags */ CAM_RETRY_SELTO
,
620 /* sense_flags */SF_RETRY_UA
,
621 &softc
->device_stats
);
624 cam_periph_unmapmem(ccb
, &mapinfo
);
626 ccb
->ccb_h
.cbfcnp
= NULL
;
627 ccb
->ccb_h
.periph_priv
= inccb
->ccb_h
.periph_priv
;
628 bcopy(ccb
, inccb
, sizeof(union ccb
));
634 passerror(union ccb
*ccb
, u_int32_t cam_flags
, u_int32_t sense_flags
)
636 struct cam_periph
*periph
;
637 struct pass_softc
*softc
;
639 periph
= xpt_path_periph(ccb
->ccb_h
.path
);
640 softc
= (struct pass_softc
*)periph
->softc
;
642 return(cam_periph_error(ccb
, cam_flags
, sense_flags
,