diff -u /dev/null sys/dev/ata/atapi-cam.c
--- /dev/null	Tue Mar 19 13:19:40 2002
+++ sys/dev/ata/atapi-cam.c	Tue Mar 19 13:16:21 2002
@@ -0,0 +1,508 @@
+/*-
+ * Copyright (c) 2001, 2002 Thomas Quinot <thomas@cuivre.fr.eu.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD:$
+ */
+
+/*
+ * A SIM (SCSI Interface Module) that provides access to ATAPI
+ * devices through CAM.
+ *
+ * This module owes much to Sergey Babkin's document
+ * 'Writing a CAM SCSI controller (A.K.A. Host Bus Adapter) driver',
+ * http://www.daemonnews.org/200006/cam-driver.html
+ *
+ */
+
+/* ATA headers used in atapi-cam.h */
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/systm.h>
+#include <dev/ata/ata-all.h>
+#include <dev/ata/atapi-all.h>
+#include <dev/ata/atapi-cam.h>
+
+#include <cam/cam_xpt_sim.h>
+#include <cam/cam_debug.h>
+#include <cam/scsi/scsi_all.h>
+
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+
+/* Private data associated with an ATAPI bus */
+struct atapi_xpt_softc {
+    struct ata_channel *ata_scp;
+    struct ata_device *devices[2];
+    struct cam_path *wpath;
+    struct cam_sim *sim;
+    int flags;
+};
+
+#define RESOURCE_SHORTAGE 1
+
+struct atapi_hcb {
+    struct atapi_xpt_softc *softc;
+    int unit;
+    int bus;
+    int target;
+    int lun;
+    union ccb *ccb;
+    u_int8_t cmd[CAM_MAX_CDBLEN];
+    int flags;
+    char *dxfer_alloc;
+};
+
+#define DOING_AUTOSENSE 1
+
+static MALLOC_DEFINE(M_ATACAM, "ATA CAM transport", "ATA driver CAM-XPT layer");
+
+/* Internal functions */
+static void atapi_action (struct cam_sim *sim, union ccb *ccb);
+static void atapi_action1 (struct cam_sim *sim, union ccb *ccb);
+static void atapi_poll (struct cam_sim *sim);
+static void atapi_async (void *callback_arg, u_int32_t code, struct cam_path *path, void *arg);
+static void atapi_async1 (void *callback_arg, u_int32_t code, struct cam_path *path, void *arg);
+static int atapi_cb (struct atapi_request *);
+static void free_hcb_and_ccb_done(struct atapi_hcb *hcb, union ccb *ccb, u_int32_t status);
+static struct atapi_hcb *allocate_hcb (struct atapi_xpt_softc *softc, int unit, int bus);
+static void free_hcb (struct atapi_hcb *hcb);
+
+struct cam_sim *atapi_cam_attach_bus (struct ata_channel *ata_scp) {
+    struct atapi_xpt_softc *scp = NULL;
+    struct cam_devq *devq = NULL;
+    struct cam_sim *sim = NULL;
+    int bus_registered = 0;
+    struct cam_path *path = NULL;
+
+    int unit;
+    struct ccb_setasync csa;
+    
+    /* Allocate our private control structure. */
+    if ((scp = malloc (sizeof (struct atapi_xpt_softc), M_ATACAM, M_NOWAIT|M_ZERO)) == NULL) {
+	goto error;
+    }
+    
+    scp->ata_scp = ata_scp;
+    scp->devices[ATA_DEV(ATA_MASTER)] = NULL;
+    scp->devices[ATA_DEV(ATA_SLAVE)] = NULL;
+    scp->flags = 0;
+    unit = device_get_unit (ata_scp->dev);
+    
+    /* Alloc one devq (either for the whole driver or for each bus). */
+    if ((devq = cam_simq_alloc(16)) == NULL) {
+	goto error;
+    }
+    
+    /* Alloc a SIM descriptor for each bus. */
+    if ((sim = cam_sim_alloc (atapi_action, atapi_poll, "atapi",
+			      (void *) scp, unit, 1, 1, devq)) == NULL) {
+	goto error;
+    }
+
+    /* Register the SIM. */
+    if(xpt_bus_register(sim, 0) != CAM_SUCCESS) {
+	goto error;
+    }
+    bus_registered = 1;
+
+    if(xpt_create_path(&path, /*periph*/NULL,
+		       cam_sim_path(sim), CAM_TARGET_WILDCARD,
+		       CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
+	goto error;
+    }
+
+    scp->wpath = path;
+    scp->sim = sim;
+
+    xpt_print_path (path);
+    printf ("Registered SIM for ata%d\n", unit);
+
+    /* Register callback for AC_LOST_DEVICE event. */
+    xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
+    csa.ccb_h.func_code = XPT_SASYNC_CB;
+    csa.event_enable = AC_LOST_DEVICE;
+    csa.callback = atapi_async;
+    csa.callback_arg = sim;
+    xpt_action((union ccb *)&csa);
+    
+    return sim;
+
+ error:
+    if (bus_registered == 1)
+        xpt_bus_deregister(cam_sim_path(sim));
+    if (sim != NULL)
+	cam_sim_free(sim, /*free_devq*/ FALSE);
+    if (devq != NULL)
+	cam_simq_free(devq);
+    if (scp != NULL)
+	free (scp, M_ATACAM);
+    return NULL;
+}
+ 
+void atapi_cam_attach_dev (struct cam_sim *sim, struct ata_device *atp) {
+    struct atapi_xpt_softc *softc = (struct atapi_xpt_softc *) cam_sim_softc (sim);
+
+    ata_set_name (atp, "atapicam",
+      2 * cam_sim_unit (sim) + (atp->unit == ATA_MASTER) ? 0 : 1);
+    softc->devices[ATA_DEV(atp->unit)] = atp;
+}
+
+static void atapi_action (struct cam_sim *sim, union ccb *ccb) {
+    int s = splcam ();
+    atapi_action1 (sim, ccb);
+    splx (s);
+}
+
+static void atapi_action1 (struct cam_sim *sim, union ccb *ccb) {
+    struct atapi_xpt_softc *softc = (struct atapi_xpt_softc *) cam_sim_softc (sim);
+    struct ccb_hdr *ccb_h = &ccb->ccb_h;
+    int unit = cam_sim_unit (sim);
+    int bus = cam_sim_bus (sim);
+    int len;
+    char *buf;
+    struct atapi_hcb *hcb = NULL;
+    
+    switch (ccb_h->func_code) {
+    case XPT_PATH_INQ:
+	{
+	    struct ccb_pathinq *cpi = &ccb->cpi;
+
+	    cpi->version_num = 1;
+	    cpi->hba_inquiry = 0;
+	    cpi->hba_misc = 0;
+	    cpi->hba_eng_cnt = 0;
+	    bzero (cpi->vuhba_flags, sizeof (cpi->vuhba_flags));
+	    cpi->max_target = 7;
+	    cpi->max_lun = 7;
+	    cpi->async_flags = 0;
+	    cpi->hpath_id = 0;
+	    cpi->initiator_id = 7;
+	    strncpy (cpi->sim_vid, "ATAPI-SIM", sizeof cpi->sim_vid);
+	    strncpy (cpi->hba_vid, "ATAPI", sizeof cpi->hba_vid);
+	    strncpy (cpi->dev_name, cam_sim_name (sim), sizeof cpi->dev_name);
+	    cpi->unit_number = cam_sim_unit (sim);
+	    cpi->bus_id = cam_sim_bus (sim);
+	    cpi->base_transfer_speed = 3300;
+
+	    ccb->ccb_h.status = CAM_REQ_CMP;
+	    xpt_done (ccb);
+	    return;
+	}
+    case XPT_RESET_DEV:	
+	/* Should reset the device. For now, do nothing. */
+#ifdef CAMDEBUG
+	xpt_print_path (ccb->ccb_h.path);
+	printf ("dev reset");
+#endif
+	ccb->ccb_h.status = CAM_REQ_CMP;
+	xpt_done (ccb);
+	return;
+    case XPT_RESET_BUS:
+	/* Should reset the ATA bus. For now, do nothing. */
+#ifdef CAMDEBUG
+	xpt_print_path (ccb->ccb_h.path);
+	printf ("bus reset");
+#endif
+	ccb->ccb_h.status = CAM_REQ_CMP;
+	xpt_done (ccb);
+	return;
+    case XPT_SET_TRAN_SETTINGS:
+	/* Ignore these. We're not doing SCSI here. */
+	ccb->ccb_h.status = CAM_REQ_CMP;
+	xpt_done (ccb);
+	return;
+    case XPT_GET_TRAN_SETTINGS:
+	{
+	    struct ccb_trans_settings *cts = &ccb->cts;
+	    cts->flags |=
+		(0
+		 | CCB_TRANS_SYNC_RATE_VALID
+		 | CCB_TRANS_SYNC_OFFSET_VALID
+		 | CCB_TRANS_BUS_WIDTH_VALID
+		 | CCB_TRANS_DISC_VALID
+		 | CCB_TRANS_TQ_VALID);
+	    cts->flags &= ~(CCB_TRANS_DISC_ENB | CCB_TRANS_TAG_ENB);
+	    cts->sync_period = 0;
+	    cts->sync_offset = 0;
+	    cts->bus_width = 8;
+
+	    ccb->ccb_h.status = CAM_REQ_CMP;
+	    xpt_done (ccb);
+	    return;
+	}	    
+    case XPT_SCSI_IO:
+	{
+	    struct ccb_scsiio *csio = &ccb->csio;
+	    int error, tid = ccb_h->target_id, lid = ccb_h->target_lun;
+#ifdef CAMDEBUG
+	    char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1];
+
+	    printf ("XPT_SCSI_IO (b%d u%d t%d l%d)\n", bus, unit, tid, lid);
+#endif
+	    /* Check that this request was not aborted already. */
+	    if ((ccb_h->status & CAM_STATUS_MASK) != CAM_REQ_INPROG) {
+#ifdef CAMDEBUG
+		printf ("Already in progress.\n");
+#endif
+		xpt_done(ccb);
+		return;
+	    }
+
+	    if (tid > 1 || softc->devices[tid] == NULL) {
+#ifdef CAMDEBUG
+		printf ("Invalid target %d.\n", tid);
+#endif
+		ccb_h->status = CAM_TID_INVALID;
+		xpt_done(ccb);
+		return;
+	    }
+#if 0
+	    /* XXX how to determine that??? */
+	    if (lid > OUR_MAX_SUPPORTED_LUN) {
+		ccb_h->status = CAM_LUN_INVALID;
+		xpt_done(ccb);
+		return;
+	    }
+#else
+	    /* -> while we dunno, be conservative. */
+	    if (lid > 0) {
+#ifdef CAMDEBUG
+		printf ("Invalid LUN %d.\n", lid);
+#endif
+		ccb_h->status = CAM_LUN_INVALID;
+		xpt_done(ccb);
+		return;
+	    }
+#endif
+	    if ((ccb_h->flags & CAM_SCATTER_VALID)) {
+		/* Scatter-gather not supported. */
+		xpt_print_path (ccb_h->path);
+		printf ("ATAPI-CAM does not support scatter-gather yet!\n");
+		break;
+	    }
+	    
+	    if ((hcb = allocate_hcb (softc, unit, bus)) == NULL) {
+		goto action_oom;
+	    }
+
+	    hcb->ccb = ccb;
+	    ccb_h->status |= CAM_SIM_QUEUED;
+
+	    bcopy ((ccb_h->flags & CAM_CDB_POINTER) ?
+		csio->cdb_io.cdb_ptr :
+		csio->cdb_io.cdb_bytes,
+	      hcb->cmd,
+	      csio->cdb_len);
+#ifdef CAMDEBUG
+	    printf ("hcb@%p: %s\n",
+		hcb,
+		scsi_cdb_string (hcb->cmd, cdb_str, sizeof (cdb_str)));
+#endif
+
+	    /* Some SCSI commands require special processing.    */
+
+	    switch (hcb->cmd[0]) {
+	    case MODE_SELECT_6:
+		/* FALLTHROUGH */
+	    case MODE_SENSE_6:
+		/* Not supported by ATAPI/MMC devices (per SCSI    */
+		/* MMC spec) translate to _10 equivalent.          */
+		/* (actually we should do this only if we have     */
+		/* tried MODE_foo_6 and received                   */
+		/* ILLEGAL_REQUEST/INVALID COMMAND OPERATION CODE) */
+
+		/* Alternative fix: behave like a honest CAM transport, */
+		/* do not muck with CDB contents, and change scsi_cd to */
+		/* always use MODE_SENSE_10 in cdgetmode(), or let      */
+		/* scsi_cd know that this specific unit is an ATAPI/MMC */
+		/* one, and in /that case/ use MODE_SENSE_10.		*/
+
+#ifdef CAMDEBUG
+		xpt_print_path (ccb_h->path);
+		printf ("Translating %s into _10 equivalent.\n",
+			(hcb->cmd[0] == MODE_SELECT_6) ? "MODE_SELECT_6" : "MODE_SENSE_6");
+#endif
+
+		if (hcb->cmd[0] == MODE_SELECT_6) {
+		    hcb->cmd[0] = MODE_SELECT_10;
+		} else {
+		    hcb->cmd[0] = MODE_SENSE_10;
+		}
+		hcb->cmd[6] = 0;
+		hcb->cmd[7] = 0;
+		hcb->cmd[8] = hcb->cmd[4];
+		hcb->cmd[9] = hcb->cmd[5];
+		hcb->cmd[4] = 0;
+		hcb->cmd[5] = 0;
+		break;
+	    }
+
+	    len = csio->dxfer_len;
+	    buf = csio->data_ptr;
+
+	    if ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN && (len & 1)) {
+		/* ATA always transfers an even number of bytes. */
+		if ((buf = hcb->dxfer_alloc = malloc
+                      (++len, M_ATACAM, M_NOWAIT|M_ZERO)) == NULL)
+		    goto action_oom;
+	    }
+	    error = atapi_queue_cmd
+		(softc->devices[tid],
+		 hcb->cmd, buf, len,
+		 ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN) ? ATPR_F_READ : 0,
+		 ccb_h->timeout, atapi_cb, (void *) hcb);
+
+	    if (error != 0) {
+		free_hcb (hcb);
+		break;
+	    }
+	    return;
+	}
+    default:
+	printf ("atapi-cam: unsupported function code %02x\n", ccb_h->func_code);
+	break;
+    }
+    ccb_h->status = CAM_REQ_INVALID;
+    xpt_done(ccb);
+
+action_oom:
+    if (hcb != NULL)
+	free_hcb (hcb);
+    xpt_print_path (ccb_h->path);
+    printf ("Out of memory: freezing queue.");
+    softc->flags |= RESOURCE_SHORTAGE;
+    xpt_freeze_simq(sim, /*count*/1);
+    ccb_h->status = CAM_REQUEUE_REQ;
+    xpt_done(ccb);
+}
+ 
+static void atapi_poll (struct cam_sim *sim) {
+    /* Do nothing - we do not actually service any
+       interrupts. */
+    printf ("atapi_poll called!\n");
+};
+
+int atapi_cb (struct atapi_request *req) {
+    int s = splcam ();
+    struct atapi_hcb *hcb = (struct atapi_hcb *) req->driver;
+    /* int targ = hcb->target; */
+    /* int ccb_status; */
+    int hcb_status = req->result;
+    struct ccb_scsiio *csio = &hcb->ccb->csio;
+
+#ifdef CAMDEBUG
+    printf ("atapi_cb: hcb@%p status = %02x: (sk = %02x%s%s%s)\n",
+      hcb, hcb_status, hcb_status >> 4,
+      (hcb_status & 4) ? " ABRT" : "",
+      (hcb_status & 2) ? " EOM" : "",
+      (hcb_status & 1) ? " ILI" : "");
+    printf("  %s: cmd %02x - sk=%02x asc=%02x ascq=%02x\n",
+      req->device->name, req->ccb[0], req->sense.sense_key,
+      req->sense.asc, req->sense.ascq);
+#endif
+
+    if (hcb_status != 0) {
+
+	hcb->ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
+
+	if ((hcb->ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0) {
+	    hcb->ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
+	    bcopy ((void *) &req->sense, (void *) &csio->sense_data,
+		   sizeof (struct atapi_reqsense));
+	}
+	free_hcb_and_ccb_done (hcb, hcb->ccb, CAM_SCSI_STATUS_ERROR);
+    } else {
+	if (((hcb->ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
+	    && hcb->dxfer_alloc != NULL)
+	    bcopy (hcb->dxfer_alloc, csio->data_ptr, csio->dxfer_len);
+	hcb->ccb->csio.scsi_status = SCSI_STATUS_OK;
+	free_hcb_and_ccb_done (hcb, hcb->ccb, CAM_REQ_CMP);
+    }
+    splx (s);
+    return 0;
+};
+
+static void
+free_hcb_and_ccb_done(struct atapi_hcb *hcb, union ccb *ccb, u_int32_t status) {
+    struct atapi_xpt_softc *softc = hcb->softc;
+    
+    if(hcb != NULL) {
+#if 0
+	untimeout(xxx_timeout, (caddr_t) hcb, ccb->ccb_h.timeout_ch);
+#endif
+	/* we're about to free a hcb, so the shortage has ended */
+	if(softc->flags & RESOURCE_SHORTAGE)  {
+	    softc->flags &= ~RESOURCE_SHORTAGE;
+	    status |= CAM_RELEASE_SIMQ;
+	}
+	free_hcb(hcb); /* also removes hcb from any internal lists */
+    }
+    ccb->ccb_h.status = status | (ccb->ccb_h.status & ~(CAM_STATUS_MASK|CAM_SIM_QUEUED));
+    xpt_done(ccb);
+}
+
+static void atapi_async (void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) {
+    int s = splcam ();
+    atapi_async1 (callback_arg, code, path, arg);
+    splx (s);
+}
+
+static void atapi_async1 (void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) {
+    struct atapi_xpt_softc *softc;
+    struct cam_sim *sim;
+    int targ;
+
+    sim = (struct cam_sim *) callback_arg;
+    softc = (struct atapi_xpt_softc *) cam_sim_softc(sim);
+    switch (code) {
+    case AC_LOST_DEVICE:
+        targ = xpt_path_target_id (path);
+	printf ("Lost target %u ???\n", targ);
+        break;
+    default:
+        break;
+    }
+}
+
+static struct atapi_hcb *allocate_hcb (struct atapi_xpt_softc *softc, int unit, int bus) {
+    struct atapi_hcb *hcb = (struct atapi_hcb *)
+	malloc (sizeof (struct atapi_hcb), M_ATACAM, M_NOWAIT|M_ZERO);
+
+    if (hcb != NULL) {
+	hcb->softc = softc;
+	hcb->unit = unit;
+	hcb->bus = bus;
+    }
+
+    return hcb;
+}
+
+static void free_hcb (struct atapi_hcb *hcb) {
+    if (hcb->dxfer_alloc != NULL)
+	free (hcb->dxfer_alloc, M_ATACAM);
+    free (hcb, M_ATACAM);
+}
diff -u /dev/null sys/dev/ata/atapi-cam.h
--- /dev/null	Tue Mar 19 13:19:40 2002
+++ sys/dev/ata/atapi-cam.h	Tue Mar 19 13:16:21 2002
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2001, 2002 Thomas Quinot <thomas@cuivre.fr.eu.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD:$
+ */
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_sim.h>
+
+struct cam_sim *atapi_cam_attach_bus (struct ata_channel *ata_scp);
+void atapi_cam_attach_dev (struct cam_sim *sim, struct ata_device *atp);
diff -u sys/cam/cam_xpt.c.dist sys/cam/cam_xpt.c
--- sys/cam/cam_xpt.c.dist	Thu Mar  7 00:33:38 2002
+++ sys/cam/cam_xpt.c	Sun Mar 17 18:35:55 2002
@@ -194,6 +194,7 @@
 #define	CAM_QUIRK_NOLUNS	0x01
 #define	CAM_QUIRK_NOSERIAL	0x02
 #define	CAM_QUIRK_HILUNS	0x04
+#define	CAM_QUIRK_NOFULLINQ	0x08
 	u_int mintags;
 	u_int maxtags;
 };
@@ -214,6 +215,7 @@
 static const char samsung[] = "SAMSUNG";
 static const char seagate[] = "SEAGATE";
 static const char microp[] = "MICROP";
+static const char toshiba[] = "TOSHIBA";
 
 static struct xpt_quirk_entry xpt_quirk_table[] = 
 {
@@ -411,6 +413,14 @@
 	},
 	{
 		/*
+		 * Many ATAPI Toshiba drives incorrectly generate a
+		 * UNIT ATTENTION condition when asked for full inquiry info.
+		 */
+		{ T_CDROM, SIP_MEDIA_REMOVABLE, toshiba, "DVD-ROM SD-M*", "*" },
+		CAM_QUIRK_NOFULLINQ, /*mintags*/0, /*maxtags*/0
+	},
+	{
+		/*
 		 * This drive doesn't like multiple LUN probing.
 		 * Submitted by:  Parag Patel <parag@cgt.com>
 		 */
@@ -5504,16 +5514,17 @@
 				 * the amount of information the device
 				 * is willing to give.
 				 */
+				xpt_find_quirk(path->device);
 				alen = inq_buf->additional_length;
 				if (softc->action == PROBE_INQUIRY
-				 && alen > (SHORT_INQUIRY_LENGTH - 4)) {
+				 && alen > (SHORT_INQUIRY_LENGTH - 4)
+				 && (path->device->quirk->quirks
+				     & CAM_QUIRK_NOFULLINQ) == 0) {
 					softc->action = PROBE_FULL_INQUIRY;
 					xpt_release_ccb(done_ccb);
 					xpt_schedule(periph, priority);
 					return;
 				}
-
-				xpt_find_quirk(path->device);
 
 				if ((inq_buf->flags & SID_CmdQue) != 0)
 					softc->action = PROBE_MODE_SENSE;

Index: sys/dev/ata/ata-all.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/ata/ata-all.c,v
retrieving revision 1.130
diff -u -r1.130 ata-all.c
--- sys/dev/ata/ata-all.c	12 Feb 2002 13:21:51 -0000	1.130
+++ sys/dev/ata/ata-all.c	28 Feb 2002 13:24:47 -0000
@@ -53,6 +53,9 @@
 #include <dev/ata/ata-disk.h>
 #include <dev/ata/ata-raid.h>
 #include <dev/ata/atapi-all.h>
+#ifdef ATAPICAM
+#include <dev/ata/atapi-cam.h>
+#endif
 
 /* device structures */
 static	d_ioctl_t	ataioctl;
@@ -202,6 +205,17 @@
 	    atapi_attach(&ch->device[MASTER]);
 	if (ch->devices & ATA_ATAPI_SLAVE)
 	    atapi_attach(&ch->device[SLAVE]);
+#ifdef ATAPICAM
+      if (ch->devices & (ATA_ATAPI_MASTER | ATA_ATAPI_SLAVE)) {
+	  struct cam_sim *sim;
+
+	  sim = atapi_cam_attach_bus (ch);
+	  if (ch->devices & ATA_ATAPI_MASTER)
+		atapi_cam_attach_dev (sim, &ch->device[MASTER]);
+	  if (ch->devices & ATA_ATAPI_SLAVE)
+		atapi_cam_attach_dev (sim, &ch->device[SLAVE]);
+      }
+#endif
 #endif
 	/* we should probe & attach RAID's here as well SOS XXX */
     }
@@ -542,6 +556,17 @@
 	    atapi_attach(&ch->device[MASTER]);
 	if (ch->devices & ATA_ATAPI_SLAVE)
 	    atapi_attach(&ch->device[SLAVE]);
+#ifdef ATAPICAM
+        if (ch->devices & (ATA_ATAPI_MASTER | ATA_ATAPI_SLAVE)) {
+	    struct cam_sim *sim;
+
+	    sim = atapi_cam_attach_bus (ch);
+	    if (ch->devices & ATA_ATAPI_MASTER)
+		atapi_cam_attach_dev (sim, &ch->device[MASTER]);
+	    if (ch->devices & ATA_ATAPI_SLAVE)
+		atapi_cam_attach_dev (sim, &ch->device[SLAVE]);
+        }
+#endif
     }
 #endif
 }
