162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Support for emulating SAT (ata pass through) on devices based 462306a36Sopenharmony_ci * on the Cypress USB/ATA bridge supporting ATACB. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (c) 2008 Matthieu Castet (castet.matthieu@free.fr) 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <scsi/scsi.h> 1162306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h> 1262306a36Sopenharmony_ci#include <scsi/scsi_eh.h> 1362306a36Sopenharmony_ci#include <linux/ata.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "usb.h" 1662306a36Sopenharmony_ci#include "protocol.h" 1762306a36Sopenharmony_ci#include "scsiglue.h" 1862306a36Sopenharmony_ci#include "debug.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define DRV_NAME "ums-cypress" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ciMODULE_DESCRIPTION("SAT support for Cypress USB/ATA bridges with ATACB"); 2362306a36Sopenharmony_ciMODULE_AUTHOR("Matthieu Castet <castet.matthieu@free.fr>"); 2462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2562306a36Sopenharmony_ciMODULE_IMPORT_NS(USB_STORAGE); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* 2862306a36Sopenharmony_ci * The table of devices 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_ci#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ 3162306a36Sopenharmony_ci vendorName, productName, useProtocol, useTransport, \ 3262306a36Sopenharmony_ci initFunction, flags) \ 3362306a36Sopenharmony_ci{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ 3462306a36Sopenharmony_ci .driver_info = (flags) } 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic struct usb_device_id cypress_usb_ids[] = { 3762306a36Sopenharmony_ci# include "unusual_cypress.h" 3862306a36Sopenharmony_ci { } /* Terminating entry */ 3962306a36Sopenharmony_ci}; 4062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, cypress_usb_ids); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#undef UNUSUAL_DEV 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* 4562306a36Sopenharmony_ci * The flags table 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_ci#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ 4862306a36Sopenharmony_ci vendor_name, product_name, use_protocol, use_transport, \ 4962306a36Sopenharmony_ci init_function, Flags) \ 5062306a36Sopenharmony_ci{ \ 5162306a36Sopenharmony_ci .vendorName = vendor_name, \ 5262306a36Sopenharmony_ci .productName = product_name, \ 5362306a36Sopenharmony_ci .useProtocol = use_protocol, \ 5462306a36Sopenharmony_ci .useTransport = use_transport, \ 5562306a36Sopenharmony_ci .initFunction = init_function, \ 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic struct us_unusual_dev cypress_unusual_dev_list[] = { 5962306a36Sopenharmony_ci# include "unusual_cypress.h" 6062306a36Sopenharmony_ci { } /* Terminating entry */ 6162306a36Sopenharmony_ci}; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#undef UNUSUAL_DEV 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/* 6762306a36Sopenharmony_ci * ATACB is a protocol used on cypress usb<->ata bridge to 6862306a36Sopenharmony_ci * send raw ATA command over mass storage 6962306a36Sopenharmony_ci * There is a ATACB2 protocol that support LBA48 on newer chip. 7062306a36Sopenharmony_ci * More info that be found on cy7c68310_8.pdf and cy7c68300c_8.pdf 7162306a36Sopenharmony_ci * datasheet from cypress.com. 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_cistatic void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci unsigned char save_cmnd[MAX_COMMAND_SIZE]; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (likely(srb->cmnd[0] != ATA_16 && srb->cmnd[0] != ATA_12)) { 7862306a36Sopenharmony_ci usb_stor_transparent_scsi_command(srb, us); 7962306a36Sopenharmony_ci return; 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci memcpy(save_cmnd, srb->cmnd, sizeof(save_cmnd)); 8362306a36Sopenharmony_ci memset(srb->cmnd, 0, MAX_COMMAND_SIZE); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* check if we support the command */ 8662306a36Sopenharmony_ci if (save_cmnd[1] >> 5) /* MULTIPLE_COUNT */ 8762306a36Sopenharmony_ci goto invalid_fld; 8862306a36Sopenharmony_ci /* check protocol */ 8962306a36Sopenharmony_ci switch ((save_cmnd[1] >> 1) & 0xf) { 9062306a36Sopenharmony_ci case 3: /*no DATA */ 9162306a36Sopenharmony_ci case 4: /* PIO in */ 9262306a36Sopenharmony_ci case 5: /* PIO out */ 9362306a36Sopenharmony_ci break; 9462306a36Sopenharmony_ci default: 9562306a36Sopenharmony_ci goto invalid_fld; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci /* first build the ATACB command */ 9962306a36Sopenharmony_ci srb->cmd_len = 16; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci srb->cmnd[0] = 0x24; /* 10262306a36Sopenharmony_ci * bVSCBSignature : vendor-specific command 10362306a36Sopenharmony_ci * this value can change, but most(all ?) manufacturers 10462306a36Sopenharmony_ci * keep the cypress default : 0x24 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_ci srb->cmnd[1] = 0x24; /* bVSCBSubCommand : 0x24 for ATACB */ 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci srb->cmnd[3] = 0xff - 1; /* 10962306a36Sopenharmony_ci * features, sector count, lba low, lba med 11062306a36Sopenharmony_ci * lba high, device, command are valid 11162306a36Sopenharmony_ci */ 11262306a36Sopenharmony_ci srb->cmnd[4] = 1; /* TransferBlockCount : 512 */ 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci if (save_cmnd[0] == ATA_16) { 11562306a36Sopenharmony_ci srb->cmnd[ 6] = save_cmnd[ 4]; /* features */ 11662306a36Sopenharmony_ci srb->cmnd[ 7] = save_cmnd[ 6]; /* sector count */ 11762306a36Sopenharmony_ci srb->cmnd[ 8] = save_cmnd[ 8]; /* lba low */ 11862306a36Sopenharmony_ci srb->cmnd[ 9] = save_cmnd[10]; /* lba med */ 11962306a36Sopenharmony_ci srb->cmnd[10] = save_cmnd[12]; /* lba high */ 12062306a36Sopenharmony_ci srb->cmnd[11] = save_cmnd[13]; /* device */ 12162306a36Sopenharmony_ci srb->cmnd[12] = save_cmnd[14]; /* command */ 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (save_cmnd[1] & 0x01) {/* extended bit set for LBA48 */ 12462306a36Sopenharmony_ci /* this could be supported by atacb2 */ 12562306a36Sopenharmony_ci if (save_cmnd[3] || save_cmnd[5] || save_cmnd[7] || save_cmnd[9] 12662306a36Sopenharmony_ci || save_cmnd[11]) 12762306a36Sopenharmony_ci goto invalid_fld; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci } else { /* ATA12 */ 13062306a36Sopenharmony_ci srb->cmnd[ 6] = save_cmnd[3]; /* features */ 13162306a36Sopenharmony_ci srb->cmnd[ 7] = save_cmnd[4]; /* sector count */ 13262306a36Sopenharmony_ci srb->cmnd[ 8] = save_cmnd[5]; /* lba low */ 13362306a36Sopenharmony_ci srb->cmnd[ 9] = save_cmnd[6]; /* lba med */ 13462306a36Sopenharmony_ci srb->cmnd[10] = save_cmnd[7]; /* lba high */ 13562306a36Sopenharmony_ci srb->cmnd[11] = save_cmnd[8]; /* device */ 13662306a36Sopenharmony_ci srb->cmnd[12] = save_cmnd[9]; /* command */ 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci /* Filter SET_FEATURES - XFER MODE command */ 14062306a36Sopenharmony_ci if ((srb->cmnd[12] == ATA_CMD_SET_FEATURES) 14162306a36Sopenharmony_ci && (srb->cmnd[6] == SETFEATURES_XFER)) 14262306a36Sopenharmony_ci goto invalid_fld; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci if (srb->cmnd[12] == ATA_CMD_ID_ATA || srb->cmnd[12] == ATA_CMD_ID_ATAPI) 14562306a36Sopenharmony_ci srb->cmnd[2] |= (1<<7); /* set IdentifyPacketDevice for these cmds */ 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci usb_stor_transparent_scsi_command(srb, us); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* if the device doesn't support ATACB */ 15162306a36Sopenharmony_ci if (srb->result == SAM_STAT_CHECK_CONDITION && 15262306a36Sopenharmony_ci memcmp(srb->sense_buffer, usb_stor_sense_invalidCDB, 15362306a36Sopenharmony_ci sizeof(usb_stor_sense_invalidCDB)) == 0) { 15462306a36Sopenharmony_ci usb_stor_dbg(us, "cypress atacb not supported ???\n"); 15562306a36Sopenharmony_ci goto end; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci /* 15962306a36Sopenharmony_ci * if ck_cond flags is set, and there wasn't critical error, 16062306a36Sopenharmony_ci * build the special sense 16162306a36Sopenharmony_ci */ 16262306a36Sopenharmony_ci if ((srb->result != (DID_ERROR << 16) && 16362306a36Sopenharmony_ci srb->result != (DID_ABORT << 16)) && 16462306a36Sopenharmony_ci save_cmnd[2] & 0x20) { 16562306a36Sopenharmony_ci struct scsi_eh_save ses; 16662306a36Sopenharmony_ci unsigned char regs[8]; 16762306a36Sopenharmony_ci unsigned char *sb = srb->sense_buffer; 16862306a36Sopenharmony_ci unsigned char *desc = sb + 8; 16962306a36Sopenharmony_ci int tmp_result; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* build the command for reading the ATA registers */ 17262306a36Sopenharmony_ci scsi_eh_prep_cmnd(srb, &ses, NULL, 0, sizeof(regs)); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci /* 17562306a36Sopenharmony_ci * we use the same command as before, but we set 17662306a36Sopenharmony_ci * the read taskfile bit, for not executing atacb command, 17762306a36Sopenharmony_ci * but reading register selected in srb->cmnd[4] 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_ci srb->cmd_len = 16; 18062306a36Sopenharmony_ci srb->cmnd[2] = 1; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci usb_stor_transparent_scsi_command(srb, us); 18362306a36Sopenharmony_ci memcpy(regs, srb->sense_buffer, sizeof(regs)); 18462306a36Sopenharmony_ci tmp_result = srb->result; 18562306a36Sopenharmony_ci scsi_eh_restore_cmnd(srb, &ses); 18662306a36Sopenharmony_ci /* we fail to get registers, report invalid command */ 18762306a36Sopenharmony_ci if (tmp_result != SAM_STAT_GOOD) 18862306a36Sopenharmony_ci goto invalid_fld; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* build the sense */ 19162306a36Sopenharmony_ci memset(sb, 0, SCSI_SENSE_BUFFERSIZE); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci /* set sk, asc for a good command */ 19462306a36Sopenharmony_ci sb[1] = RECOVERED_ERROR; 19562306a36Sopenharmony_ci sb[2] = 0; /* ATA PASS THROUGH INFORMATION AVAILABLE */ 19662306a36Sopenharmony_ci sb[3] = 0x1D; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci /* 19962306a36Sopenharmony_ci * XXX we should generate sk, asc, ascq from status and error 20062306a36Sopenharmony_ci * regs 20162306a36Sopenharmony_ci * (see 11.1 Error translation ATA device error to SCSI error 20262306a36Sopenharmony_ci * map, and ata_to_sense_error from libata.) 20362306a36Sopenharmony_ci */ 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci /* Sense data is current and format is descriptor. */ 20662306a36Sopenharmony_ci sb[0] = 0x72; 20762306a36Sopenharmony_ci desc[0] = 0x09; /* ATA_RETURN_DESCRIPTOR */ 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* set length of additional sense data */ 21062306a36Sopenharmony_ci sb[7] = 14; 21162306a36Sopenharmony_ci desc[1] = 12; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci /* Copy registers into sense buffer. */ 21462306a36Sopenharmony_ci desc[ 2] = 0x00; 21562306a36Sopenharmony_ci desc[ 3] = regs[1]; /* features */ 21662306a36Sopenharmony_ci desc[ 5] = regs[2]; /* sector count */ 21762306a36Sopenharmony_ci desc[ 7] = regs[3]; /* lba low */ 21862306a36Sopenharmony_ci desc[ 9] = regs[4]; /* lba med */ 21962306a36Sopenharmony_ci desc[11] = regs[5]; /* lba high */ 22062306a36Sopenharmony_ci desc[12] = regs[6]; /* device */ 22162306a36Sopenharmony_ci desc[13] = regs[7]; /* command */ 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci srb->result = SAM_STAT_CHECK_CONDITION; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci goto end; 22662306a36Sopenharmony_ciinvalid_fld: 22762306a36Sopenharmony_ci srb->result = SAM_STAT_CHECK_CONDITION; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci memcpy(srb->sense_buffer, 23062306a36Sopenharmony_ci usb_stor_sense_invalidCDB, 23162306a36Sopenharmony_ci sizeof(usb_stor_sense_invalidCDB)); 23262306a36Sopenharmony_ciend: 23362306a36Sopenharmony_ci memcpy(srb->cmnd, save_cmnd, sizeof(save_cmnd)); 23462306a36Sopenharmony_ci if (srb->cmnd[0] == ATA_12) 23562306a36Sopenharmony_ci srb->cmd_len = 12; 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic struct scsi_host_template cypress_host_template; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic int cypress_probe(struct usb_interface *intf, 24162306a36Sopenharmony_ci const struct usb_device_id *id) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci struct us_data *us; 24462306a36Sopenharmony_ci int result; 24562306a36Sopenharmony_ci struct usb_device *device; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci result = usb_stor_probe1(&us, intf, id, 24862306a36Sopenharmony_ci (id - cypress_usb_ids) + cypress_unusual_dev_list, 24962306a36Sopenharmony_ci &cypress_host_template); 25062306a36Sopenharmony_ci if (result) 25162306a36Sopenharmony_ci return result; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* 25462306a36Sopenharmony_ci * Among CY7C68300 chips, the A revision does not support Cypress ATACB 25562306a36Sopenharmony_ci * Filter out this revision from EEPROM default descriptor values 25662306a36Sopenharmony_ci */ 25762306a36Sopenharmony_ci device = interface_to_usbdev(intf); 25862306a36Sopenharmony_ci if (device->descriptor.iManufacturer != 0x38 || 25962306a36Sopenharmony_ci device->descriptor.iProduct != 0x4e || 26062306a36Sopenharmony_ci device->descriptor.iSerialNumber != 0x64) { 26162306a36Sopenharmony_ci us->protocol_name = "Transparent SCSI with Cypress ATACB"; 26262306a36Sopenharmony_ci us->proto_handler = cypress_atacb_passthrough; 26362306a36Sopenharmony_ci } else { 26462306a36Sopenharmony_ci us->protocol_name = "Transparent SCSI"; 26562306a36Sopenharmony_ci us->proto_handler = usb_stor_transparent_scsi_command; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci result = usb_stor_probe2(us); 26962306a36Sopenharmony_ci return result; 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic struct usb_driver cypress_driver = { 27362306a36Sopenharmony_ci .name = DRV_NAME, 27462306a36Sopenharmony_ci .probe = cypress_probe, 27562306a36Sopenharmony_ci .disconnect = usb_stor_disconnect, 27662306a36Sopenharmony_ci .suspend = usb_stor_suspend, 27762306a36Sopenharmony_ci .resume = usb_stor_resume, 27862306a36Sopenharmony_ci .reset_resume = usb_stor_reset_resume, 27962306a36Sopenharmony_ci .pre_reset = usb_stor_pre_reset, 28062306a36Sopenharmony_ci .post_reset = usb_stor_post_reset, 28162306a36Sopenharmony_ci .id_table = cypress_usb_ids, 28262306a36Sopenharmony_ci .soft_unbind = 1, 28362306a36Sopenharmony_ci .no_dynamic_id = 1, 28462306a36Sopenharmony_ci}; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cimodule_usb_stor_driver(cypress_driver, cypress_host_template, DRV_NAME); 287