Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Support for emulating SAT (ata pass through) on devices based
0004  *       on the Cypress USB/ATA bridge supporting ATACB.
0005  *
0006  * Copyright (c) 2008 Matthieu Castet (castet.matthieu@free.fr)
0007  */
0008 
0009 #include <linux/module.h>
0010 #include <scsi/scsi.h>
0011 #include <scsi/scsi_cmnd.h>
0012 #include <scsi/scsi_eh.h>
0013 #include <linux/ata.h>
0014 
0015 #include "usb.h"
0016 #include "protocol.h"
0017 #include "scsiglue.h"
0018 #include "debug.h"
0019 
0020 #define DRV_NAME "ums-cypress"
0021 
0022 MODULE_DESCRIPTION("SAT support for Cypress USB/ATA bridges with ATACB");
0023 MODULE_AUTHOR("Matthieu Castet <castet.matthieu@free.fr>");
0024 MODULE_LICENSE("GPL");
0025 MODULE_IMPORT_NS(USB_STORAGE);
0026 
0027 /*
0028  * The table of devices
0029  */
0030 #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
0031             vendorName, productName, useProtocol, useTransport, \
0032             initFunction, flags) \
0033 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
0034   .driver_info = (flags) }
0035 
0036 static struct usb_device_id cypress_usb_ids[] = {
0037 #   include "unusual_cypress.h"
0038     { }     /* Terminating entry */
0039 };
0040 MODULE_DEVICE_TABLE(usb, cypress_usb_ids);
0041 
0042 #undef UNUSUAL_DEV
0043 
0044 /*
0045  * The flags table
0046  */
0047 #define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
0048             vendor_name, product_name, use_protocol, use_transport, \
0049             init_function, Flags) \
0050 { \
0051     .vendorName = vendor_name,  \
0052     .productName = product_name,    \
0053     .useProtocol = use_protocol,    \
0054     .useTransport = use_transport,  \
0055     .initFunction = init_function,  \
0056 }
0057 
0058 static struct us_unusual_dev cypress_unusual_dev_list[] = {
0059 #   include "unusual_cypress.h"
0060     { }     /* Terminating entry */
0061 };
0062 
0063 #undef UNUSUAL_DEV
0064 
0065 
0066 /*
0067  * ATACB is a protocol used on cypress usb<->ata bridge to
0068  * send raw ATA command over mass storage
0069  * There is a ATACB2 protocol that support LBA48 on newer chip.
0070  * More info that be found on cy7c68310_8.pdf and cy7c68300c_8.pdf
0071  * datasheet from cypress.com.
0072  */
0073 static void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us)
0074 {
0075     unsigned char save_cmnd[MAX_COMMAND_SIZE];
0076 
0077     if (likely(srb->cmnd[0] != ATA_16 && srb->cmnd[0] != ATA_12)) {
0078         usb_stor_transparent_scsi_command(srb, us);
0079         return;
0080     }
0081 
0082     memcpy(save_cmnd, srb->cmnd, sizeof(save_cmnd));
0083     memset(srb->cmnd, 0, MAX_COMMAND_SIZE);
0084 
0085     /* check if we support the command */
0086     if (save_cmnd[1] >> 5) /* MULTIPLE_COUNT */
0087         goto invalid_fld;
0088     /* check protocol */
0089     switch ((save_cmnd[1] >> 1) & 0xf) {
0090     case 3: /*no DATA */
0091     case 4: /* PIO in */
0092     case 5: /* PIO out */
0093         break;
0094     default:
0095         goto invalid_fld;
0096     }
0097 
0098     /* first build the ATACB command */
0099     srb->cmd_len = 16;
0100 
0101     srb->cmnd[0] = 0x24; /*
0102                   * bVSCBSignature : vendor-specific command
0103                   * this value can change, but most(all ?) manufacturers
0104                   * keep the cypress default : 0x24
0105                   */
0106     srb->cmnd[1] = 0x24; /* bVSCBSubCommand : 0x24 for ATACB */
0107 
0108     srb->cmnd[3] = 0xff - 1; /*
0109                   * features, sector count, lba low, lba med
0110                   * lba high, device, command are valid
0111                   */
0112     srb->cmnd[4] = 1; /* TransferBlockCount : 512 */
0113 
0114     if (save_cmnd[0] == ATA_16) {
0115         srb->cmnd[ 6] = save_cmnd[ 4]; /* features */
0116         srb->cmnd[ 7] = save_cmnd[ 6]; /* sector count */
0117         srb->cmnd[ 8] = save_cmnd[ 8]; /* lba low */
0118         srb->cmnd[ 9] = save_cmnd[10]; /* lba med */
0119         srb->cmnd[10] = save_cmnd[12]; /* lba high */
0120         srb->cmnd[11] = save_cmnd[13]; /* device */
0121         srb->cmnd[12] = save_cmnd[14]; /* command */
0122 
0123         if (save_cmnd[1] & 0x01) {/* extended bit set for LBA48 */
0124             /* this could be supported by atacb2 */
0125             if (save_cmnd[3] || save_cmnd[5] || save_cmnd[7] || save_cmnd[9]
0126                     || save_cmnd[11])
0127                 goto invalid_fld;
0128         }
0129     } else { /* ATA12 */
0130         srb->cmnd[ 6] = save_cmnd[3]; /* features */
0131         srb->cmnd[ 7] = save_cmnd[4]; /* sector count */
0132         srb->cmnd[ 8] = save_cmnd[5]; /* lba low */
0133         srb->cmnd[ 9] = save_cmnd[6]; /* lba med */
0134         srb->cmnd[10] = save_cmnd[7]; /* lba high */
0135         srb->cmnd[11] = save_cmnd[8]; /* device */
0136         srb->cmnd[12] = save_cmnd[9]; /* command */
0137 
0138     }
0139     /* Filter SET_FEATURES - XFER MODE command */
0140     if ((srb->cmnd[12] == ATA_CMD_SET_FEATURES)
0141             && (srb->cmnd[6] == SETFEATURES_XFER))
0142         goto invalid_fld;
0143 
0144     if (srb->cmnd[12] == ATA_CMD_ID_ATA || srb->cmnd[12] == ATA_CMD_ID_ATAPI)
0145         srb->cmnd[2] |= (1<<7); /* set  IdentifyPacketDevice for these cmds */
0146 
0147 
0148     usb_stor_transparent_scsi_command(srb, us);
0149 
0150     /* if the device doesn't support ATACB */
0151     if (srb->result == SAM_STAT_CHECK_CONDITION &&
0152             memcmp(srb->sense_buffer, usb_stor_sense_invalidCDB,
0153                 sizeof(usb_stor_sense_invalidCDB)) == 0) {
0154         usb_stor_dbg(us, "cypress atacb not supported ???\n");
0155         goto end;
0156     }
0157 
0158     /*
0159      * if ck_cond flags is set, and there wasn't critical error,
0160      * build the special sense
0161      */
0162     if ((srb->result != (DID_ERROR << 16) &&
0163                 srb->result != (DID_ABORT << 16)) &&
0164             save_cmnd[2] & 0x20) {
0165         struct scsi_eh_save ses;
0166         unsigned char regs[8];
0167         unsigned char *sb = srb->sense_buffer;
0168         unsigned char *desc = sb + 8;
0169         int tmp_result;
0170 
0171         /* build the command for reading the ATA registers */
0172         scsi_eh_prep_cmnd(srb, &ses, NULL, 0, sizeof(regs));
0173 
0174         /*
0175          * we use the same command as before, but we set
0176          * the read taskfile bit, for not executing atacb command,
0177          * but reading register selected in srb->cmnd[4]
0178          */
0179         srb->cmd_len = 16;
0180         srb->cmnd[2] = 1;
0181 
0182         usb_stor_transparent_scsi_command(srb, us);
0183         memcpy(regs, srb->sense_buffer, sizeof(regs));
0184         tmp_result = srb->result;
0185         scsi_eh_restore_cmnd(srb, &ses);
0186         /* we fail to get registers, report invalid command */
0187         if (tmp_result != SAM_STAT_GOOD)
0188             goto invalid_fld;
0189 
0190         /* build the sense */
0191         memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
0192 
0193         /* set sk, asc for a good command */
0194         sb[1] = RECOVERED_ERROR;
0195         sb[2] = 0; /* ATA PASS THROUGH INFORMATION AVAILABLE */
0196         sb[3] = 0x1D;
0197 
0198         /*
0199          * XXX we should generate sk, asc, ascq from status and error
0200          * regs
0201          * (see 11.1 Error translation ATA device error to SCSI error
0202          * map, and ata_to_sense_error from libata.)
0203          */
0204 
0205         /* Sense data is current and format is descriptor. */
0206         sb[0] = 0x72;
0207         desc[0] = 0x09; /* ATA_RETURN_DESCRIPTOR */
0208 
0209         /* set length of additional sense data */
0210         sb[7] = 14;
0211         desc[1] = 12;
0212 
0213         /* Copy registers into sense buffer. */
0214         desc[ 2] = 0x00;
0215         desc[ 3] = regs[1];  /* features */
0216         desc[ 5] = regs[2];  /* sector count */
0217         desc[ 7] = regs[3];  /* lba low */
0218         desc[ 9] = regs[4];  /* lba med */
0219         desc[11] = regs[5];  /* lba high */
0220         desc[12] = regs[6];  /* device */
0221         desc[13] = regs[7];  /* command */
0222 
0223         srb->result = SAM_STAT_CHECK_CONDITION;
0224     }
0225     goto end;
0226 invalid_fld:
0227     srb->result = SAM_STAT_CHECK_CONDITION;
0228 
0229     memcpy(srb->sense_buffer,
0230             usb_stor_sense_invalidCDB,
0231             sizeof(usb_stor_sense_invalidCDB));
0232 end:
0233     memcpy(srb->cmnd, save_cmnd, sizeof(save_cmnd));
0234     if (srb->cmnd[0] == ATA_12)
0235         srb->cmd_len = 12;
0236 }
0237 
0238 static struct scsi_host_template cypress_host_template;
0239 
0240 static int cypress_probe(struct usb_interface *intf,
0241              const struct usb_device_id *id)
0242 {
0243     struct us_data *us;
0244     int result;
0245     struct usb_device *device;
0246 
0247     result = usb_stor_probe1(&us, intf, id,
0248             (id - cypress_usb_ids) + cypress_unusual_dev_list,
0249             &cypress_host_template);
0250     if (result)
0251         return result;
0252 
0253     /*
0254      * Among CY7C68300 chips, the A revision does not support Cypress ATACB
0255      * Filter out this revision from EEPROM default descriptor values
0256      */
0257     device = interface_to_usbdev(intf);
0258     if (device->descriptor.iManufacturer != 0x38 ||
0259         device->descriptor.iProduct != 0x4e ||
0260         device->descriptor.iSerialNumber != 0x64) {
0261         us->protocol_name = "Transparent SCSI with Cypress ATACB";
0262         us->proto_handler = cypress_atacb_passthrough;
0263     } else {
0264         us->protocol_name = "Transparent SCSI";
0265         us->proto_handler = usb_stor_transparent_scsi_command;
0266     }
0267 
0268     result = usb_stor_probe2(us);
0269     return result;
0270 }
0271 
0272 static struct usb_driver cypress_driver = {
0273     .name =     DRV_NAME,
0274     .probe =    cypress_probe,
0275     .disconnect =   usb_stor_disconnect,
0276     .suspend =  usb_stor_suspend,
0277     .resume =   usb_stor_resume,
0278     .reset_resume = usb_stor_reset_resume,
0279     .pre_reset =    usb_stor_pre_reset,
0280     .post_reset =   usb_stor_post_reset,
0281     .id_table = cypress_usb_ids,
0282     .soft_unbind =  1,
0283     .no_dynamic_id = 1,
0284 };
0285 
0286 module_usb_stor_driver(cypress_driver, cypress_host_template, DRV_NAME);