summaryrefslogtreecommitdiffstats
path: root/sys/cam/scsi/scsi_pass.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/cam/scsi/scsi_pass.c')
-rw-r--r--sys/cam/scsi/scsi_pass.c48
1 files changed, 45 insertions, 3 deletions
diff --git a/sys/cam/scsi/scsi_pass.c b/sys/cam/scsi/scsi_pass.c
index 927b1b8..2f5d973 100644
--- a/sys/cam/scsi/scsi_pass.c
+++ b/sys/cam/scsi/scsi_pass.c
@@ -24,7 +24,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: scsi_pass.c,v 1.5 1998/11/22 23:44:47 ken Exp $
+ * $Id: scsi_pass.c,v 1.6 1999/02/10 00:03:15 ken Exp $
*/
#include <sys/param.h>
@@ -703,13 +703,55 @@ passioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
{
union ccb *inccb;
union ccb *ccb;
+ int ccb_malloced;
inccb = (union ccb *)addr;
- ccb = cam_periph_getccb(periph, inccb->ccb_h.pinfo.priority);
+
+ /*
+ * Some CCB types, like scan bus and scan lun can only go
+ * through the transport layer device.
+ */
+ if (inccb->ccb_h.func_code & XPT_FC_XPT_ONLY) {
+ xpt_print_path(periph->path);
+ printf("CCB function code %#x is restricted to the "
+ "XPT device\n", inccb->ccb_h.func_code);
+ error = ENODEV;
+ break;
+ }
+
+ /*
+ * Non-immediate CCBs need a CCB from the per-device pool
+ * of CCBs, which is scheduled by the transport layer.
+ * Immediate CCBs and user-supplied CCBs should just be
+ * malloced.
+ */
+ if ((inccb->ccb_h.func_code & XPT_FC_QUEUED)
+ && ((inccb->ccb_h.func_code & XPT_FC_USER_CCB) == 0)) {
+ ccb = cam_periph_getccb(periph,
+ inccb->ccb_h.pinfo.priority);
+ ccb_malloced = 0;
+ } else {
+ ccb = xpt_alloc_ccb();
+
+ if (ccb != NULL)
+ xpt_setup_ccb(&ccb->ccb_h, periph->path,
+ inccb->ccb_h.pinfo.priority);
+ ccb_malloced = 1;
+ }
+
+ if (ccb == NULL) {
+ xpt_print_path(periph->path);
+ printf("unable to allocate CCB\n");
+ error = ENOMEM;
+ break;
+ }
error = passsendccb(periph, ccb, inccb);
- xpt_release_ccb(ccb);
+ if (ccb_malloced)
+ xpt_free_ccb(ccb);
+ else
+ xpt_release_ccb(ccb);
break;
}
OpenPOWER on IntegriCloud