diff options
-rw-r--r-- | sys/dev/usb/umass.c | 362 |
1 files changed, 231 insertions, 131 deletions
diff --git a/sys/dev/usb/umass.c b/sys/dev/usb/umass.c index f598544..92b6103 100644 --- a/sys/dev/usb/umass.c +++ b/sys/dev/usb/umass.c @@ -45,7 +45,7 @@ * - UFI (floppy command set) * - 8070i (ATA/ATAPI) * - * UFI and 8070i are transformed versions of the SCSI command set. The + * UFI and 8070i (ATAPI) are transformed versions of the SCSI command set. The * sc->transform method is used to convert the commands into the appropriate * format (if at all necessary). For example, UFI requires all commands to be * 12 bytes in length amongst other things. @@ -61,7 +61,7 @@ * - CAM (Common Access Method) * - SCSI * - UFI - * - 8070i + * - 8070i (ATAPI) * * The protocols are implemented using a state machine, for the transfers as * well as for the resets. The state machine is contained in umass_*_state. @@ -85,10 +85,17 @@ */ /* XXX Should we split the driver into a number of files? umass.c, - * umass_scsi.c, umass_8070.c, umass_ufi.c, umass_bbb.c, umass_cbi.c or + * umass_scsi.c, umass_atapi.c, umass_ufi.c, umass_bbb.c, umass_cbi.c or * something similar? */ +/* + * XXX Currently CBI with CCI is not supported because it bombs the system + * when the device is detached (low frequency interrupts are detached + * too late. + */ +#undef CBI_I + #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> @@ -109,10 +116,8 @@ #include <cam/scsi/scsi_all.h> #include <cam/scsi/scsi_da.h> -#ifdef UMASS_DO_CAM_RESCAN #include <sys/devicestat.h> #include <cam/cam_periph.h> -#endif #ifdef UMASS_DEBUG #define DIF(m, x) if (umassdebug & (m)) do { x ; } while (0) @@ -120,7 +125,7 @@ #define UDMASS_GEN 0x00010000 /* general */ #define UDMASS_SCSI 0x00020000 /* scsi */ #define UDMASS_UFI 0x00040000 /* ufi command set */ -#define UDMASS_8070 0x00080000 /* 8070i command set */ +#define UDMASS_ATAPI 0x00080000 /* 8070i command set */ #define UDMASS_USB 0x00100000 /* USB general */ #define UDMASS_BBB 0x00200000 /* Bulk-Only transfers */ #define UDMASS_CBI 0x00400000 /* CBI transfers */ @@ -141,7 +146,7 @@ int umassdebug = UDMASS_ALL; /* device name */ #define DEVNAME "umass" -#define DEVNAME_SIM "umass-" +#define DEVNAME_SIM "umass-sim" #define UMASS_MAX_TRANSFER_SIZE 65536 #define UMASS_DEFAULT_TRANSFER_SPEED 150 /* in kb/s, conservative est. */ @@ -152,7 +157,7 @@ int umassdebug = UDMASS_ALL; /* CAM specific definitions */ -/* The bus id, whatever that is */ +/* We only have one bus */ #define UMASS_SCSI_BUS 0 /* All USB drives are 'connected' to one SIM (SCSI controller). umass3 @@ -287,7 +292,7 @@ struct umass_softc { # define PROTO_CBI_I 0x0004 # define PROTO_WIRE 0x00ff /* USB wire protocol mask */ # define PROTO_SCSI 0x0100 /* command protocol */ -# define PROTO_8070 0x0200 +# define PROTO_ATAPI 0x0200 # define PROTO_UFI 0x0400 # define PROTO_COMMAND 0xff00 /* command protocol mask */ @@ -389,6 +394,7 @@ struct umass_softc { /* SCSI/CAM specific variables */ + unsigned char cam_scsi_command[CAM_MAX_CDBLEN]; struct scsi_sense cam_scsi_sense; int transfer_speed; /* in kb/s */ @@ -420,7 +426,6 @@ char *states[TSTATE_STATES+1] = { #endif struct cam_sim *umass_sim; /* SCSI Interface Module */ -struct cam_path *umass_path; /* and its path */ /* USB device probe/attach/detach functions */ @@ -474,9 +479,9 @@ static void umass_cam_cb __P((struct umass_softc *sc, void *priv, static void umass_cam_sense_cb __P((struct umass_softc *sc, void *priv, int residue, int status)); -#ifdef UMASS_DO_CAM_RESCAN +static void umass_cam_rescan_callback + __P((struct cam_periph *periph,union ccb *ccb)); static void umass_cam_rescan __P((struct umass_softc *sc)); -#endif static int umass_cam_attach_sim __P((void)); static int umass_cam_attach __P((struct umass_softc *sc)); @@ -490,12 +495,14 @@ static int umass_scsi_transform __P((struct umass_softc *sc, unsigned char **rcmd, int *rcmdlen)); /* UFI specific functions */ +#define UFI_COMMAND_LENGTH 12 /* UFI commands are always 12b */ static int umass_ufi_transform __P((struct umass_softc *sc, unsigned char *cmd, int cmdlen, unsigned char **rcmd, int *rcmdlen)); -/* 8070 specific functions */ -static int umass_8070_transform __P((struct umass_softc *sc, +/* ATAPI (8070i) specific functions */ +#define ATAPI_COMMAND_LENGTH 12 /* ATAPI commands are always 12b */ +static int umass_atapi_transform __P((struct umass_softc *sc, unsigned char *cmd, int cmdlen, unsigned char **rcmd, int *rcmdlen)); @@ -544,9 +551,9 @@ umass_match_proto(struct umass_softc *sc, usbd_interface_handle iface) && UGETW(dd->idProduct) == USB_PRODUCT_SHUTTLE_EUSB) { sc->drive = SHUTTLE_EUSB; #if CBI_I - sc->proto = PROTO_8070 | PROTO_CBI_I; + sc->proto = PROTO_ATAPI | PROTO_CBI_I; #else - sc->proto = PROTO_8070 | PROTO_CBI; + sc->proto = PROTO_ATAPI | PROTO_CBI; #endif return UMATCH_VENDOR_PRODUCT; } @@ -593,7 +600,7 @@ umass_match_proto(struct umass_softc *sc, usbd_interface_handle iface) sc->proto |= PROTO_UFI; break; case USUBCLASS_SFF8070I: - sc->proto |= PROTO_8070; + sc->proto |= PROTO_ATAPI; break; default: DPRINTF(UDMASS_GEN, ("%s: Unsupported command protocol %d\n", @@ -671,8 +678,8 @@ USB_ATTACH(umass) case PROTO_SCSI: printf("SCSI"); break; - case PROTO_8070: - printf("8070i"); + case PROTO_ATAPI: + printf("8070i (ATAPI)"); break; case PROTO_UFI: printf("UFI"); @@ -819,8 +826,8 @@ USB_ATTACH(umass) sc->transform = umass_scsi_transform; else if (sc->proto & PROTO_UFI) sc->transform = umass_ufi_transform; - else if (sc->proto & PROTO_8070) - sc->transform = umass_8070_transform; + else if (sc->proto & PROTO_ATAPI) + sc->transform = umass_atapi_transform; #ifdef UMASS_DEBUG else panic("No transformation defined for command proto 0x%02x\n", @@ -830,7 +837,7 @@ USB_ATTACH(umass) /* From here onwards the device can be used. */ if ((sc->proto & PROTO_SCSI) || - (sc->proto & PROTO_8070) || + (sc->proto & PROTO_ATAPI) || (sc->proto & PROTO_UFI)) { /* Prepare the SCSI command block */ sc->cam_scsi_sense.opcode = REQUEST_SENSE; @@ -855,6 +862,7 @@ USB_ATTACH(umass) __FILE__, __LINE__, sc->proto); } + DPRINTF(UDMASS_GEN, ("%s: Attach finished\n", USBDEVNAME(sc->sc_dev))); USB_ATTACH_SUCCESS_RETURN; @@ -871,7 +879,7 @@ USB_DETACH(umass) sc->flags |= UMASS_FLAGS_GONE; if ((sc->proto & PROTO_SCSI) || - (sc->proto & PROTO_8070) || + (sc->proto & PROTO_ATAPI) || (sc->proto & PROTO_UFI)) /* detach the device from the SCSI host controller (SIM) */ err = umass_cam_detach(sc); @@ -1815,7 +1823,7 @@ umass_cbi_state(usbd_xfer_handle xfer, usbd_private_handle priv, /* - * CAM specific functions (used by SCSI, UFI, 8070) + * CAM specific functions (used by SCSI, UFI, 8070 (ATAPI)) */ static int @@ -1826,17 +1834,15 @@ umass_cam_attach_sim() /* A HBA is attached to the CAM layer. * * The CAM layer will then after a while start probing for - * devices on the bus. The number of devices is limitted to one. + * devices on the bus. The number of SIMs is limitted to one. */ - /* SCSI transparent command set */ - devq = cam_simq_alloc(1 /*maximum openings*/); if (devq == NULL) return(ENOMEM); - umass_sim = cam_sim_alloc(umass_cam_action, umass_cam_poll, DEVNAME, - NULL /*priv*/, 0 /*unit number*/, + umass_sim = cam_sim_alloc(umass_cam_action, umass_cam_poll, DEVNAME_SIM, + NULL /*priv*/, UMASS_SCSIID_HOST/*unit number*/, 1 /*maximum device openings*/, 0 /*maximum tagged device openings*/, devq); @@ -1845,39 +1851,23 @@ umass_cam_attach_sim() return(ENOMEM); } - if(xpt_bus_register(umass_sim, 0) != CAM_SUCCESS) - return(ENOMEM); - - if (xpt_create_path(&umass_path, NULL, cam_sim_path(umass_sim), - UMASS_SCSIID_HOST, 0) - != CAM_REQ_CMP) + if(xpt_bus_register(umass_sim, UMASS_SCSI_BUS) != CAM_SUCCESS) return(ENOMEM); return(0); } -#ifdef UMASS_DO_CAM_RESCAN -/* this function is only used from umass_cam_rescan, so mention - * prototype down here. - */ -static void umass_cam_rescan_callback(struct cam_periph *periph,union ccb *ccb); - static void umass_cam_rescan_callback(struct cam_periph *periph, union ccb *ccb) { #ifdef UMASS_DEBUG - struct umass_softc *sc = devclass_get_softc(umass_devclass, - ccb->ccb_h.target_id); - if (ccb->ccb_h.status != CAM_REQ_CMP) { - DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d: Rescan failed, 0x%04x\n", - USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS, - ccb->ccb_h.target_id, ccb->ccb_h.target_lun, + DPRINTF(UDMASS_SCSI, ("scbus%d: Rescan failed, 0x%04x\n", + cam_sim_path(umass_sim), ccb->ccb_h.status)); } else { - DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d: Rescan succeeded, freeing resources.\n", - USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS, - ccb->ccb_h.target_id, ccb->ccb_h.target_lun)); + DPRINTF(UDMASS_SCSI, ("scbus%d: Rescan succeeded\n", + cam_sim_path(umass_sim))); } #endif @@ -1890,16 +1880,39 @@ umass_cam_rescan(struct umass_softc *sc) { struct cam_path *path; union ccb *ccb = malloc(sizeof(union ccb), M_USBDEV, M_WAITOK); + struct cam_periph *periph; memset(ccb, 0, sizeof(union ccb)); - DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d: scanning bus for new device %d\n", - USBDEVNAME(sc->sc_dev), cam_sim_path(umass_sim), - device_get_unit(sc->sc_dev), 0, - device_get_unit(sc->sc_dev))); + DPRINTF(UDMASS_SCSI, ("scbus%d: scanning for %s:%d:%d:%d\n", + cam_sim_path(umass_sim), + USBDEVNAME(sc->sc_dev), cam_sim_path(umass_sim), + USBDEVUNIT(sc->sc_dev), CAM_LUN_WILDCARD)); + + /* Lookup the peripheral for the SIM */ + if (xpt_create_path(&path, NULL, cam_sim_path(umass_sim), + UMASS_SCSIID_HOST, 0) + != CAM_REQ_CMP) + return; + periph = cam_periph_find(path, cam_sim_name(umass_sim)); +#ifdef UMASS_DO_CAM_RESCAN + if (periph == NULL) { + DPRINTF(UDMASS_SCSI, ("scbus%d: abusing xpt_periph\n", + cam_sim_path(umass_sim))); + periph = xpt_periph; + } +#endif + if (periph == NULL) { + DPRINTF(UDMASS_SCSI, ("scbus%d: no periph, rescan failed\n", + cam_sim_path(umass_sim))); + xpt_free_path(path); + return; + } + xpt_free_path(path); - if (xpt_create_path(&path, xpt_periph, cam_sim_path(umass_sim), - device_get_unit(sc->sc_dev), 0) + /* Lookup the path again, but now include the periph in the path */ + if (xpt_create_path(&path, periph, cam_sim_path(umass_sim), + UMASS_SCSIID_HOST, 0) != CAM_REQ_CMP) return; @@ -1911,7 +1924,6 @@ umass_cam_rescan(struct umass_softc *sc) /* The scan is in progress now. */ } -#endif static int umass_cam_attach(struct umass_softc *sc) @@ -1923,14 +1935,21 @@ umass_cam_attach(struct umass_softc *sc) /* The artificial limit UMASS_SCSIID_MAX is there because CAM expects * a limit to the number of targets that are present on a SIM. */ - if (device_get_unit(sc->sc_dev) > UMASS_SCSIID_MAX) { - printf("%s: Increase UMASS_SCSIID_MAX (currently %d) in %s " - "and try again.\n", USBDEVNAME(sc->sc_dev), - UMASS_SCSIID_MAX, __FILE__); + if (device_get_unit(sc->sc_dev) >= UMASS_SCSIID_MAX) { + printf("scbus%d: Increase UMASS_SCSIID_MAX (currently %d) in %s" + " and try again.\n", + cam_sim_path(umass_sim), UMASS_SCSIID_MAX, __FILE__); return(1); } - -#ifdef UMASS_DO_CAM_RESCAN + +#ifndef UMASS_DEBUG + if (bootverbose) +#endif + printf("%s:%d:%d:%d: Attached to scbus%d as device %d\n", + USBDEVNAME(sc->sc_dev), cam_sim_path(umass_sim), + USBDEVUNIT(sc->sc_dev), CAM_LUN_WILDCARD, + cam_sim_path(umass_sim), USBDEVUNIT(sc->sc_dev)); + if (!cold) { /* Notify CAM of the new device. Any failure is benign, as the * user can still do it by hand (camcontrol rescan <busno>). @@ -1940,7 +1959,6 @@ umass_cam_attach(struct umass_softc *sc) */ umass_cam_rescan(sc); } -#endif return(0); /* always succesfull */ } @@ -1955,14 +1973,6 @@ umass_cam_detach_sim() if (umass_sim) return(EBUSY); /* XXX CAM can't handle disappearing SIMs yet */ - if (umass_path) { - /* XXX do we need to send an asynchroneous event for the SIM? - xpt_async(AC_LOST_DEVICE, umass_path, NULL); - */ - xpt_free_path(umass_path); - umass_path = NULL; - } - if (umass_sim) { if (xpt_bus_deregister(cam_sim_path(umass_sim))) cam_sim_free(umass_sim, /*free_devq*/TRUE); @@ -1981,11 +1991,12 @@ umass_cam_detach(struct umass_softc *sc) struct cam_path *path; /* detach of sim not done until module unload */ - DPRINTF(UDMASS_SCSI, ("%s: losing CAM device entry\n", - USBDEVNAME(sc->sc_dev))); + DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d: losing CAM device entry\n", + USBDEVNAME(sc->sc_dev), cam_sim_path(umass_sim), + USBDEVUNIT(sc->sc_dev), CAM_LUN_WILDCARD)); if (xpt_create_path(&path, NULL, cam_sim_path(umass_sim), - device_get_unit(sc->sc_dev), CAM_LUN_WILDCARD) + USBDEVUNIT(sc->sc_dev), CAM_LUN_WILDCARD) != CAM_REQ_CMP) return(ENOMEM); xpt_async(AC_LOST_DEVICE, path, NULL); @@ -2012,7 +2023,7 @@ umass_cam_action(struct cam_sim *sim, union ccb *ccb) if (sc && (sc->flags & UMASS_FLAGS_GONE)) { DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:func_code 0x%04x: " "Invalid target (gone)\n", - USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS, + USBDEVNAME(sc->sc_dev), cam_sim_path(umass_sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun, ccb->ccb_h.func_code)); ccb->ccb_h.status = CAM_TID_INVALID; @@ -2037,7 +2048,7 @@ umass_cam_action(struct cam_sim *sim, union ccb *ccb) if (sc == NULL) { printf("%s:%d:%d:%d:func_code 0x%04x: " "Invalid target\n", - DEVNAME_SIM, UMASS_SCSI_BUS, + DEVNAME_SIM, cam_sim_path(umass_sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun, ccb->ccb_h.func_code); @@ -2055,7 +2066,7 @@ umass_cam_action(struct cam_sim *sim, union ccb *ccb) if (sc == NULL && ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) { DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:func_code 0x%04x: " "Invalid target\n", - DEVNAME_SIM, UMASS_SCSI_BUS, + DEVNAME_SIM, cam_sim_path(umass_sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun, ccb->ccb_h.func_code)); @@ -2076,11 +2087,13 @@ umass_cam_action(struct cam_sim *sim, union ccb *ccb) int dir; unsigned char *cmd; int cmdlen; + unsigned char *rcmd; + int rcmdlen; DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_SCSI_IO: " "cmd: 0x%02x, flags: 0x%02x, " "%db cmd/%db data/%db sense\n", - USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS, + USBDEVNAME(sc->sc_dev), cam_sim_path(umass_sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun, csio->cdb_io.cdb_bytes[0], ccb->ccb_h.flags & CAM_DIR_MASK, @@ -2098,7 +2111,7 @@ umass_cam_action(struct cam_sim *sim, union ccb *ccb) if (sc->transfer_state != TSTATE_IDLE) { DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_SCSI_IO: " "I/O requested while busy (state %d, %s)\n", - USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS, + USBDEVNAME(sc->sc_dev), cam_sim_path(umass_sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun, sc->transfer_state,states[sc->transfer_state])); ccb->ccb_h.status = CAM_SCSI_BUSY; @@ -2118,9 +2131,27 @@ umass_cam_action(struct cam_sim *sim, union ccb *ccb) } ccb->ccb_h.status = CAM_REQ_INPROG | CAM_SIM_QUEUED; - if (sc->transform(sc, csio->cdb_io.cdb_bytes, csio->cdb_len, - &cmd, &cmdlen)) { - sc->transfer(sc, ccb->ccb_h.target_lun, cmd, cmdlen, + + + if (csio->ccb_h.flags & CAM_CDB_POINTER) { + cmd = (unsigned char *) csio->cdb_io.cdb_ptr; + } else { + cmd = (unsigned char *) &csio->cdb_io.cdb_bytes; + } + cmdlen = csio->cdb_len; + rcmd = (unsigned char *) &sc->cam_scsi_command; + rcmdlen = sizeof(sc->cam_scsi_command); + + /* sc->transform will convert the command to the command + * (format) needed by the specific command set and return + * the converted command in a buffer pointed to be rcmd. + * We pass in a buffer, but if the command does not + * have to be transformed it returns a ptr to the original + * buffer (see umass_scsi_transform). + */ + + if (sc->transform(sc, cmd, cmdlen, &rcmd, &rcmdlen)) { + sc->transfer(sc, ccb->ccb_h.target_lun, rcmd, rcmdlen, csio->data_ptr, csio->dxfer_len, dir, umass_cam_cb, (void *) ccb); @@ -2137,7 +2168,7 @@ umass_cam_action(struct cam_sim *sim, union ccb *ccb) DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_PATH_INQ:.\n", (sc == NULL? DEVNAME_SIM:USBDEVNAME(sc->sc_dev)), - UMASS_SCSI_BUS, + cam_sim_path(umass_sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun)); /* host specific information */ @@ -2164,7 +2195,7 @@ umass_cam_action(struct cam_sim *sim, union ccb *ccb) case XPT_RESET_DEV: { DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_RESET_DEV:.\n", - USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS, + USBDEVNAME(sc->sc_dev), cam_sim_path(umass_sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun)); ccb->ccb_h.status = CAM_REQ_INPROG; @@ -2176,7 +2207,7 @@ umass_cam_action(struct cam_sim *sim, union ccb *ccb) struct ccb_trans_settings *cts = &ccb->cts; DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_GET_TRAN_SETTINGS:.\n", - USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS, + USBDEVNAME(sc->sc_dev), cam_sim_path(umass_sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun)); cts->valid = 0; @@ -2189,7 +2220,7 @@ umass_cam_action(struct cam_sim *sim, union ccb *ccb) case XPT_SET_TRAN_SETTINGS: { DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_SET_TRAN_SETTINGS:.\n", - USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS, + USBDEVNAME(sc->sc_dev), cam_sim_path(umass_sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun)); ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; @@ -2202,7 +2233,7 @@ umass_cam_action(struct cam_sim *sim, union ccb *ccb) DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_CALC_GEOMETRY: " "Volume size = %d\n", - USBDEVNAME(sc->sc_dev), UMASS_SCSI_BUS, + USBDEVNAME(sc->sc_dev), cam_sim_path(umass_sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun, ccg->volume_size)); @@ -2235,7 +2266,7 @@ umass_cam_action(struct cam_sim *sim, union ccb *ccb) { DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_NOOP:.\n", (sc == NULL? DEVNAME_SIM:USBDEVNAME(sc->sc_dev)), - UMASS_SCSI_BUS, + cam_sim_path(umass_sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun)); ccb->ccb_h.status = CAM_REQ_CMP; @@ -2246,7 +2277,7 @@ umass_cam_action(struct cam_sim *sim, union ccb *ccb) DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:func_code 0x%04x: " "Not implemented\n", (sc == NULL? DEVNAME_SIM:USBDEVNAME(sc->sc_dev)), - UMASS_SCSI_BUS, + cam_sim_path(umass_sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun, ccb->ccb_h.func_code)); @@ -2297,32 +2328,30 @@ umass_cam_cb(struct umass_softc *sc, void *priv, int residue, int status) switch (ccb->ccb_h.func_code) { case XPT_SCSI_IO: { - unsigned char *cmd; - int cmdlen; + unsigned char *rcmd; + int rcmdlen; /* fetch sense data */ DPRINTF(UDMASS_SCSI,("%s: Fetching %db sense data\n", USBDEVNAME(sc->sc_dev), sc->cam_scsi_sense.length)); + /* the rest of the command was filled in at attach */ sc->cam_scsi_sense.length = csio->sense_len; - if (sc->transform(sc, (char *) &sc->cam_scsi_sense, - sizeof(sc->cam_scsi_sense), - &cmd, &cmdlen)) { + rcmd = (unsigned char *) &sc->cam_scsi_command; + + if (sc->transform(sc, + (unsigned char *) &sc->cam_scsi_sense, + sizeof(sc->cam_scsi_sense), + &rcmd, &rcmdlen)) { sc->transfer(sc, ccb->ccb_h.target_lun, - cmd, cmdlen, + rcmd, rcmdlen, &csio->sense_data, csio->sense_len, DIR_IN, umass_cam_sense_cb, (void *) ccb); } else { -#ifdef UMASS_DEBUG panic("transform(REQUEST_SENSE) failed\n"); -#else - csio->resid = sc->transfer_datalen; - ccb->ccb_h.status = CAM_REQ_CMP_ERR; - xpt_done(ccb); -#endif } break; } @@ -2428,7 +2457,7 @@ static int umass_scsi_transform(struct umass_softc *sc, unsigned char *cmd, int cmdlen, unsigned char **rcmd, int *rcmdlen) { - *rcmd = cmd; /* trivial copy */ + *rcmd = cmd; /* We don't need to copy it */ *rcmdlen = cmdlen; return 1; /* success */ @@ -2442,52 +2471,123 @@ static int umass_ufi_transform(struct umass_softc *sc, unsigned char *cmd, int cmdlen, unsigned char **rcmd, int *rcmdlen) { - *rcmd = cmd; /* A UFI command is always 12 bytes in length */ - /* XXX cmd[(cmdlen+1)..12] contains garbage */ - *rcmdlen = 12; + KASSERT(*rcmdlen < UFI_COMMAND_LENGTH, + ("rcmdlen = %d < %d, buffer too small", + rcmdlen, UFI_COMMAND_LENGTH)); + + *rcmdlen = UFI_COMMAND_LENGTH; + memset(*rcmd, 0, UFI_COMMAND_LENGTH); + + /* Handle any quirks */ + if (cmd[0] == TEST_UNIT_READY + && sc->quirks & NO_TEST_UNIT_READY) { + /* Some devices do not support this command. + * Start Stop Unit should give the same results + */ + DPRINTF(UDMASS_UFI, ("%s: Converted TEST_UNIT_READY " + "to START_UNIT\n", USBDEVNAME(sc->sc_dev))); + cmd[0] = START_STOP_UNIT; + cmd[4] = SSS_START; + return 1; + } switch (cmd[0]) { + /* Commands of which the format has been verified. They should work. */ case TEST_UNIT_READY: - if (sc->quirks & NO_TEST_UNIT_READY) { - DPRINTF(UDMASS_UFI, ("%s: Converted TEST_UNIT_READY " - "to START_UNIT\n", USBDEVNAME(sc->sc_dev))); - cmd[0] = START_STOP_UNIT; - cmd[4] = SSS_START; - } - return 1; + case REZERO_UNIT: + case REQUEST_SENSE: case INQUIRY: case START_STOP_UNIT: - case MODE_SENSE: + case SEND_DIAGNOSTIC: case PREVENT_ALLOW: - case READ_10: - case READ_12: case READ_CAPACITY: - case REQUEST_SENSE: - case REZERO_UNIT: - case POSITION_TO_ELEMENT: /* SEEK_10 */ - case SEND_DIAGNOSTIC: + case READ_10: case WRITE_10: - case WRITE_12: - /* FORMAT_UNIT */ - /* MODE_SELECT */ - /* READ_FORMAT_CAPACITY */ - /* VERIFY */ - /* WRITE_AND_VERIFY */ + case POSITION_TO_ELEMENT: /* SEEK_10 */ + case MODE_SELECT_10: + case MODE_SENSE_10: + /* Copy the command into the (zeroed out) destination buffer */ + memcpy(*rcmd, cmd, cmdlen); return 1; /* success */ + + /* Other UFI commands: FORMAT_UNIT, MODE_SELECT, READ_FORMAT_CAPACITY, + * VERIFY, WRITE_AND_VERIFY. + * These should be checked whether they somehow can be made to fit. + */ + + /* These commands are known _not_ to work. They should be converted + * The 6 byte commands can be switched off with a CAM quirk. See + * the entry for the Y-E data drive. + */ + case READ_6: + case WRITE_6: + case MODE_SENSE_6: + case MODE_SELECT_6: + case READ_12: + case WRITE_12: default: - return 0; /* success */ + printf("%s: Unsupported UFI command 0x%02x", + USBDEVNAME(sc->sc_dev), cmd[0]); + if (cmdlen == 6) + printf(", 6 byte command should have been converted"); + printf("\n"); + return 0; /* failure */ } } /* - * 8070 specific functions + * 8070 (ATAPI) specific functions */ static int -umass_8070_transform(struct umass_softc *sc, unsigned char *cmd, int cmdlen, - unsigned char **rcmd, int *rcmdlen) +umass_atapi_transform(struct umass_softc *sc, unsigned char *cmd, int cmdlen, + unsigned char **rcmd, int *rcmdlen) { - return 0; /* failure */ + /* A ATAPI command is always 12 bytes in length */ + KASSERT(*rcmdlen < ATAPI_COMMAND_LENGTH, + ("rcmdlen = %d < %d, buffer too small", + rcmdlen, ATAPI_COMMAND_LENGTH)); + + *rcmdlen = ATAPI_COMMAND_LENGTH; + memset(*rcmd, 0, ATAPI_COMMAND_LENGTH); + + switch (cmd[0]) { + /* Commands of which the format has been verified. They should work. */ + case TEST_UNIT_READY: + case REZERO_UNIT: + case REQUEST_SENSE: + case INQUIRY: + case START_STOP_UNIT: + case SEND_DIAGNOSTIC: + case PREVENT_ALLOW: + case READ_CAPACITY: + case READ_10: + case WRITE_10: + case POSITION_TO_ELEMENT: /* SEEK_10 */ + case MODE_SELECT_10: + case MODE_SENSE_10: + /* Copy the command into the (zeroed out) destination buffer */ + memcpy(*rcmd, cmd, cmdlen); + return 1; /* success */ + + /* These commands are known _not_ to work. They should be converted + * The 6 byte commands can be switched off with a CAM quirk. See + * the entry for the Y-E data drive. + */ + case READ_6: + case WRITE_6: + case MODE_SENSE_6: + case MODE_SELECT_6: + case READ_12: + case WRITE_12: + default: + printf("%s: Unsupported ATAPI command 0x%02x", + USBDEVNAME(sc->sc_dev), cmd[0]); + if (cmdlen == 6) + printf(", 6 byte command should have been converted"); + printf("\n"); + return 0; /* failure */ + } } |