18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for Datafab USB Compact Flash reader 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * datafab driver v0.1: 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * First release 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Current development and maintenance by: 108c2ecf20Sopenharmony_ci * (c) 2000 Jimmie Mayfield (mayfield+datafab@sackheads.org) 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Many thanks to Robert Baruch for the SanDisk SmartMedia reader driver 138c2ecf20Sopenharmony_ci * which I used as a template for this driver. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Some bugfixes and scatter-gather code by Gregory P. Smith 168c2ecf20Sopenharmony_ci * (greg-usb@electricrain.com) 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * Fix for media change by Joerg Schneider (js@joergschneider.com) 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Other contributors: 218c2ecf20Sopenharmony_ci * (c) 2002 Alan Stern <stern@rowland.org> 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci/* 258c2ecf20Sopenharmony_ci * This driver attempts to support USB CompactFlash reader/writer devices 268c2ecf20Sopenharmony_ci * based on Datafab USB-to-ATA chips. It was specifically developed for the 278c2ecf20Sopenharmony_ci * Datafab MDCFE-B USB CompactFlash reader but has since been found to work 288c2ecf20Sopenharmony_ci * with a variety of Datafab-based devices from a number of manufacturers. 298c2ecf20Sopenharmony_ci * I've received a report of this driver working with a Datafab-based 308c2ecf20Sopenharmony_ci * SmartMedia device though please be aware that I'm personally unable to 318c2ecf20Sopenharmony_ci * test SmartMedia support. 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * This driver supports reading and writing. If you're truly paranoid, 348c2ecf20Sopenharmony_ci * however, you can force the driver into a write-protected state by setting 358c2ecf20Sopenharmony_ci * the WP enable bits in datafab_handle_mode_sense(). See the comments 368c2ecf20Sopenharmony_ci * in that routine. 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#include <linux/errno.h> 408c2ecf20Sopenharmony_ci#include <linux/module.h> 418c2ecf20Sopenharmony_ci#include <linux/slab.h> 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 448c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#include "usb.h" 478c2ecf20Sopenharmony_ci#include "transport.h" 488c2ecf20Sopenharmony_ci#include "protocol.h" 498c2ecf20Sopenharmony_ci#include "debug.h" 508c2ecf20Sopenharmony_ci#include "scsiglue.h" 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#define DRV_NAME "ums-datafab" 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver for Datafab USB Compact Flash reader"); 558c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jimmie Mayfield <mayfield+datafab@sackheads.org>"); 568c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 578c2ecf20Sopenharmony_ciMODULE_IMPORT_NS(USB_STORAGE); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistruct datafab_info { 608c2ecf20Sopenharmony_ci unsigned long sectors; /* total sector count */ 618c2ecf20Sopenharmony_ci unsigned long ssize; /* sector size in bytes */ 628c2ecf20Sopenharmony_ci signed char lun; /* used for dual-slot readers */ 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci /* the following aren't used yet */ 658c2ecf20Sopenharmony_ci unsigned char sense_key; 668c2ecf20Sopenharmony_ci unsigned long sense_asc; /* additional sense code */ 678c2ecf20Sopenharmony_ci unsigned long sense_ascq; /* additional sense code qualifier */ 688c2ecf20Sopenharmony_ci}; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic int datafab_determine_lun(struct us_data *us, 718c2ecf20Sopenharmony_ci struct datafab_info *info); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* 758c2ecf20Sopenharmony_ci * The table of devices 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_ci#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ 788c2ecf20Sopenharmony_ci vendorName, productName, useProtocol, useTransport, \ 798c2ecf20Sopenharmony_ci initFunction, flags) \ 808c2ecf20Sopenharmony_ci{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ 818c2ecf20Sopenharmony_ci .driver_info = (flags) } 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic struct usb_device_id datafab_usb_ids[] = { 848c2ecf20Sopenharmony_ci# include "unusual_datafab.h" 858c2ecf20Sopenharmony_ci { } /* Terminating entry */ 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, datafab_usb_ids); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci#undef UNUSUAL_DEV 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci/* 928c2ecf20Sopenharmony_ci * The flags table 938c2ecf20Sopenharmony_ci */ 948c2ecf20Sopenharmony_ci#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ 958c2ecf20Sopenharmony_ci vendor_name, product_name, use_protocol, use_transport, \ 968c2ecf20Sopenharmony_ci init_function, Flags) \ 978c2ecf20Sopenharmony_ci{ \ 988c2ecf20Sopenharmony_ci .vendorName = vendor_name, \ 998c2ecf20Sopenharmony_ci .productName = product_name, \ 1008c2ecf20Sopenharmony_ci .useProtocol = use_protocol, \ 1018c2ecf20Sopenharmony_ci .useTransport = use_transport, \ 1028c2ecf20Sopenharmony_ci .initFunction = init_function, \ 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic struct us_unusual_dev datafab_unusual_dev_list[] = { 1068c2ecf20Sopenharmony_ci# include "unusual_datafab.h" 1078c2ecf20Sopenharmony_ci { } /* Terminating entry */ 1088c2ecf20Sopenharmony_ci}; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci#undef UNUSUAL_DEV 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic inline int 1148c2ecf20Sopenharmony_cidatafab_bulk_read(struct us_data *us, unsigned char *data, unsigned int len) { 1158c2ecf20Sopenharmony_ci if (len == 0) 1168c2ecf20Sopenharmony_ci return USB_STOR_XFER_GOOD; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci usb_stor_dbg(us, "len = %d\n", len); 1198c2ecf20Sopenharmony_ci return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, 1208c2ecf20Sopenharmony_ci data, len, NULL); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic inline int 1258c2ecf20Sopenharmony_cidatafab_bulk_write(struct us_data *us, unsigned char *data, unsigned int len) { 1268c2ecf20Sopenharmony_ci if (len == 0) 1278c2ecf20Sopenharmony_ci return USB_STOR_XFER_GOOD; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci usb_stor_dbg(us, "len = %d\n", len); 1308c2ecf20Sopenharmony_ci return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, 1318c2ecf20Sopenharmony_ci data, len, NULL); 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic int datafab_read_data(struct us_data *us, 1368c2ecf20Sopenharmony_ci struct datafab_info *info, 1378c2ecf20Sopenharmony_ci u32 sector, 1388c2ecf20Sopenharmony_ci u32 sectors) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci unsigned char *command = us->iobuf; 1418c2ecf20Sopenharmony_ci unsigned char *buffer; 1428c2ecf20Sopenharmony_ci unsigned char thistime; 1438c2ecf20Sopenharmony_ci unsigned int totallen, alloclen; 1448c2ecf20Sopenharmony_ci int len, result; 1458c2ecf20Sopenharmony_ci unsigned int sg_offset = 0; 1468c2ecf20Sopenharmony_ci struct scatterlist *sg = NULL; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci // we're working in LBA mode. according to the ATA spec, 1498c2ecf20Sopenharmony_ci // we can support up to 28-bit addressing. I don't know if Datafab 1508c2ecf20Sopenharmony_ci // supports beyond 24-bit addressing. It's kind of hard to test 1518c2ecf20Sopenharmony_ci // since it requires > 8GB CF card. 1528c2ecf20Sopenharmony_ci // 1538c2ecf20Sopenharmony_ci if (sectors > 0x0FFFFFFF) 1548c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (info->lun == -1) { 1578c2ecf20Sopenharmony_ci result = datafab_determine_lun(us, info); 1588c2ecf20Sopenharmony_ci if (result != USB_STOR_TRANSPORT_GOOD) 1598c2ecf20Sopenharmony_ci return result; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci totallen = sectors * info->ssize; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci // Since we don't read more than 64 KB at a time, we have to create 1658c2ecf20Sopenharmony_ci // a bounce buffer and move the data a piece at a time between the 1668c2ecf20Sopenharmony_ci // bounce buffer and the actual transfer buffer. 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci alloclen = min(totallen, 65536u); 1698c2ecf20Sopenharmony_ci buffer = kmalloc(alloclen, GFP_NOIO); 1708c2ecf20Sopenharmony_ci if (buffer == NULL) 1718c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci do { 1748c2ecf20Sopenharmony_ci // loop, never allocate or transfer more than 64k at once 1758c2ecf20Sopenharmony_ci // (min(128k, 255*info->ssize) is the real limit) 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci len = min(totallen, alloclen); 1788c2ecf20Sopenharmony_ci thistime = (len / info->ssize) & 0xff; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci command[0] = 0; 1818c2ecf20Sopenharmony_ci command[1] = thistime; 1828c2ecf20Sopenharmony_ci command[2] = sector & 0xFF; 1838c2ecf20Sopenharmony_ci command[3] = (sector >> 8) & 0xFF; 1848c2ecf20Sopenharmony_ci command[4] = (sector >> 16) & 0xFF; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci command[5] = 0xE0 + (info->lun << 4); 1878c2ecf20Sopenharmony_ci command[5] |= (sector >> 24) & 0x0F; 1888c2ecf20Sopenharmony_ci command[6] = 0x20; 1898c2ecf20Sopenharmony_ci command[7] = 0x01; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci // send the read command 1928c2ecf20Sopenharmony_ci result = datafab_bulk_write(us, command, 8); 1938c2ecf20Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) 1948c2ecf20Sopenharmony_ci goto leave; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci // read the result 1978c2ecf20Sopenharmony_ci result = datafab_bulk_read(us, buffer, len); 1988c2ecf20Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) 1998c2ecf20Sopenharmony_ci goto leave; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci // Store the data in the transfer buffer 2028c2ecf20Sopenharmony_ci usb_stor_access_xfer_buf(buffer, len, us->srb, 2038c2ecf20Sopenharmony_ci &sg, &sg_offset, TO_XFER_BUF); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci sector += thistime; 2068c2ecf20Sopenharmony_ci totallen -= len; 2078c2ecf20Sopenharmony_ci } while (totallen > 0); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci kfree(buffer); 2108c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci leave: 2138c2ecf20Sopenharmony_ci kfree(buffer); 2148c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic int datafab_write_data(struct us_data *us, 2198c2ecf20Sopenharmony_ci struct datafab_info *info, 2208c2ecf20Sopenharmony_ci u32 sector, 2218c2ecf20Sopenharmony_ci u32 sectors) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci unsigned char *command = us->iobuf; 2248c2ecf20Sopenharmony_ci unsigned char *reply = us->iobuf; 2258c2ecf20Sopenharmony_ci unsigned char *buffer; 2268c2ecf20Sopenharmony_ci unsigned char thistime; 2278c2ecf20Sopenharmony_ci unsigned int totallen, alloclen; 2288c2ecf20Sopenharmony_ci int len, result; 2298c2ecf20Sopenharmony_ci unsigned int sg_offset = 0; 2308c2ecf20Sopenharmony_ci struct scatterlist *sg = NULL; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci // we're working in LBA mode. according to the ATA spec, 2338c2ecf20Sopenharmony_ci // we can support up to 28-bit addressing. I don't know if Datafab 2348c2ecf20Sopenharmony_ci // supports beyond 24-bit addressing. It's kind of hard to test 2358c2ecf20Sopenharmony_ci // since it requires > 8GB CF card. 2368c2ecf20Sopenharmony_ci // 2378c2ecf20Sopenharmony_ci if (sectors > 0x0FFFFFFF) 2388c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (info->lun == -1) { 2418c2ecf20Sopenharmony_ci result = datafab_determine_lun(us, info); 2428c2ecf20Sopenharmony_ci if (result != USB_STOR_TRANSPORT_GOOD) 2438c2ecf20Sopenharmony_ci return result; 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci totallen = sectors * info->ssize; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci // Since we don't write more than 64 KB at a time, we have to create 2498c2ecf20Sopenharmony_ci // a bounce buffer and move the data a piece at a time between the 2508c2ecf20Sopenharmony_ci // bounce buffer and the actual transfer buffer. 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci alloclen = min(totallen, 65536u); 2538c2ecf20Sopenharmony_ci buffer = kmalloc(alloclen, GFP_NOIO); 2548c2ecf20Sopenharmony_ci if (buffer == NULL) 2558c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci do { 2588c2ecf20Sopenharmony_ci // loop, never allocate or transfer more than 64k at once 2598c2ecf20Sopenharmony_ci // (min(128k, 255*info->ssize) is the real limit) 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci len = min(totallen, alloclen); 2628c2ecf20Sopenharmony_ci thistime = (len / info->ssize) & 0xff; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci // Get the data from the transfer buffer 2658c2ecf20Sopenharmony_ci usb_stor_access_xfer_buf(buffer, len, us->srb, 2668c2ecf20Sopenharmony_ci &sg, &sg_offset, FROM_XFER_BUF); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci command[0] = 0; 2698c2ecf20Sopenharmony_ci command[1] = thistime; 2708c2ecf20Sopenharmony_ci command[2] = sector & 0xFF; 2718c2ecf20Sopenharmony_ci command[3] = (sector >> 8) & 0xFF; 2728c2ecf20Sopenharmony_ci command[4] = (sector >> 16) & 0xFF; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci command[5] = 0xE0 + (info->lun << 4); 2758c2ecf20Sopenharmony_ci command[5] |= (sector >> 24) & 0x0F; 2768c2ecf20Sopenharmony_ci command[6] = 0x30; 2778c2ecf20Sopenharmony_ci command[7] = 0x02; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci // send the command 2808c2ecf20Sopenharmony_ci result = datafab_bulk_write(us, command, 8); 2818c2ecf20Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) 2828c2ecf20Sopenharmony_ci goto leave; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci // send the data 2858c2ecf20Sopenharmony_ci result = datafab_bulk_write(us, buffer, len); 2868c2ecf20Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) 2878c2ecf20Sopenharmony_ci goto leave; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci // read the result 2908c2ecf20Sopenharmony_ci result = datafab_bulk_read(us, reply, 2); 2918c2ecf20Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) 2928c2ecf20Sopenharmony_ci goto leave; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (reply[0] != 0x50 && reply[1] != 0) { 2958c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Gah! write return code: %02x %02x\n", 2968c2ecf20Sopenharmony_ci reply[0], reply[1]); 2978c2ecf20Sopenharmony_ci result = USB_STOR_TRANSPORT_ERROR; 2988c2ecf20Sopenharmony_ci goto leave; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci sector += thistime; 3028c2ecf20Sopenharmony_ci totallen -= len; 3038c2ecf20Sopenharmony_ci } while (totallen > 0); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci kfree(buffer); 3068c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci leave: 3098c2ecf20Sopenharmony_ci kfree(buffer); 3108c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic int datafab_determine_lun(struct us_data *us, 3158c2ecf20Sopenharmony_ci struct datafab_info *info) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci // Dual-slot readers can be thought of as dual-LUN devices. 3188c2ecf20Sopenharmony_ci // We need to determine which card slot is being used. 3198c2ecf20Sopenharmony_ci // We'll send an IDENTIFY DEVICE command and see which LUN responds... 3208c2ecf20Sopenharmony_ci // 3218c2ecf20Sopenharmony_ci // There might be a better way of doing this? 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci static unsigned char scommand[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 }; 3248c2ecf20Sopenharmony_ci unsigned char *command = us->iobuf; 3258c2ecf20Sopenharmony_ci unsigned char *buf; 3268c2ecf20Sopenharmony_ci int count = 0, rc; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (!info) 3298c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci memcpy(command, scommand, 8); 3328c2ecf20Sopenharmony_ci buf = kmalloc(512, GFP_NOIO); 3338c2ecf20Sopenharmony_ci if (!buf) 3348c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci usb_stor_dbg(us, "locating...\n"); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci // we'll try 3 times before giving up... 3398c2ecf20Sopenharmony_ci // 3408c2ecf20Sopenharmony_ci while (count++ < 3) { 3418c2ecf20Sopenharmony_ci command[5] = 0xa0; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci rc = datafab_bulk_write(us, command, 8); 3448c2ecf20Sopenharmony_ci if (rc != USB_STOR_XFER_GOOD) { 3458c2ecf20Sopenharmony_ci rc = USB_STOR_TRANSPORT_ERROR; 3468c2ecf20Sopenharmony_ci goto leave; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci rc = datafab_bulk_read(us, buf, 512); 3508c2ecf20Sopenharmony_ci if (rc == USB_STOR_XFER_GOOD) { 3518c2ecf20Sopenharmony_ci info->lun = 0; 3528c2ecf20Sopenharmony_ci rc = USB_STOR_TRANSPORT_GOOD; 3538c2ecf20Sopenharmony_ci goto leave; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci command[5] = 0xb0; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci rc = datafab_bulk_write(us, command, 8); 3598c2ecf20Sopenharmony_ci if (rc != USB_STOR_XFER_GOOD) { 3608c2ecf20Sopenharmony_ci rc = USB_STOR_TRANSPORT_ERROR; 3618c2ecf20Sopenharmony_ci goto leave; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci rc = datafab_bulk_read(us, buf, 512); 3658c2ecf20Sopenharmony_ci if (rc == USB_STOR_XFER_GOOD) { 3668c2ecf20Sopenharmony_ci info->lun = 1; 3678c2ecf20Sopenharmony_ci rc = USB_STOR_TRANSPORT_GOOD; 3688c2ecf20Sopenharmony_ci goto leave; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci msleep(20); 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci rc = USB_STOR_TRANSPORT_ERROR; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci leave: 3778c2ecf20Sopenharmony_ci kfree(buf); 3788c2ecf20Sopenharmony_ci return rc; 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic int datafab_id_device(struct us_data *us, 3828c2ecf20Sopenharmony_ci struct datafab_info *info) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci // this is a variation of the ATA "IDENTIFY DEVICE" command...according 3858c2ecf20Sopenharmony_ci // to the ATA spec, 'Sector Count' isn't used but the Windows driver 3868c2ecf20Sopenharmony_ci // sets this bit so we do too... 3878c2ecf20Sopenharmony_ci // 3888c2ecf20Sopenharmony_ci static unsigned char scommand[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 }; 3898c2ecf20Sopenharmony_ci unsigned char *command = us->iobuf; 3908c2ecf20Sopenharmony_ci unsigned char *reply; 3918c2ecf20Sopenharmony_ci int rc; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci if (!info) 3948c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci if (info->lun == -1) { 3978c2ecf20Sopenharmony_ci rc = datafab_determine_lun(us, info); 3988c2ecf20Sopenharmony_ci if (rc != USB_STOR_TRANSPORT_GOOD) 3998c2ecf20Sopenharmony_ci return rc; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci memcpy(command, scommand, 8); 4038c2ecf20Sopenharmony_ci reply = kmalloc(512, GFP_NOIO); 4048c2ecf20Sopenharmony_ci if (!reply) 4058c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci command[5] += (info->lun << 4); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci rc = datafab_bulk_write(us, command, 8); 4108c2ecf20Sopenharmony_ci if (rc != USB_STOR_XFER_GOOD) { 4118c2ecf20Sopenharmony_ci rc = USB_STOR_TRANSPORT_ERROR; 4128c2ecf20Sopenharmony_ci goto leave; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci // we'll go ahead and extract the media capacity while we're here... 4168c2ecf20Sopenharmony_ci // 4178c2ecf20Sopenharmony_ci rc = datafab_bulk_read(us, reply, 512); 4188c2ecf20Sopenharmony_ci if (rc == USB_STOR_XFER_GOOD) { 4198c2ecf20Sopenharmony_ci // capacity is at word offset 57-58 4208c2ecf20Sopenharmony_ci // 4218c2ecf20Sopenharmony_ci info->sectors = ((u32)(reply[117]) << 24) | 4228c2ecf20Sopenharmony_ci ((u32)(reply[116]) << 16) | 4238c2ecf20Sopenharmony_ci ((u32)(reply[115]) << 8) | 4248c2ecf20Sopenharmony_ci ((u32)(reply[114]) ); 4258c2ecf20Sopenharmony_ci rc = USB_STOR_TRANSPORT_GOOD; 4268c2ecf20Sopenharmony_ci goto leave; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci rc = USB_STOR_TRANSPORT_ERROR; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci leave: 4328c2ecf20Sopenharmony_ci kfree(reply); 4338c2ecf20Sopenharmony_ci return rc; 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cistatic int datafab_handle_mode_sense(struct us_data *us, 4388c2ecf20Sopenharmony_ci struct scsi_cmnd * srb, 4398c2ecf20Sopenharmony_ci int sense_6) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci static unsigned char rw_err_page[12] = { 4428c2ecf20Sopenharmony_ci 0x1, 0xA, 0x21, 1, 0, 0, 0, 0, 1, 0, 0, 0 4438c2ecf20Sopenharmony_ci }; 4448c2ecf20Sopenharmony_ci static unsigned char cache_page[12] = { 4458c2ecf20Sopenharmony_ci 0x8, 0xA, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0 4468c2ecf20Sopenharmony_ci }; 4478c2ecf20Sopenharmony_ci static unsigned char rbac_page[12] = { 4488c2ecf20Sopenharmony_ci 0x1B, 0xA, 0, 0x81, 0, 0, 0, 0, 0, 0, 0, 0 4498c2ecf20Sopenharmony_ci }; 4508c2ecf20Sopenharmony_ci static unsigned char timer_page[8] = { 4518c2ecf20Sopenharmony_ci 0x1C, 0x6, 0, 0, 0, 0 4528c2ecf20Sopenharmony_ci }; 4538c2ecf20Sopenharmony_ci unsigned char pc, page_code; 4548c2ecf20Sopenharmony_ci unsigned int i = 0; 4558c2ecf20Sopenharmony_ci struct datafab_info *info = (struct datafab_info *) (us->extra); 4568c2ecf20Sopenharmony_ci unsigned char *ptr = us->iobuf; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci // most of this stuff is just a hack to get things working. the 4598c2ecf20Sopenharmony_ci // datafab reader doesn't present a SCSI interface so we 4608c2ecf20Sopenharmony_ci // fudge the SCSI commands... 4618c2ecf20Sopenharmony_ci // 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci pc = srb->cmnd[2] >> 6; 4648c2ecf20Sopenharmony_ci page_code = srb->cmnd[2] & 0x3F; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci switch (pc) { 4678c2ecf20Sopenharmony_ci case 0x0: 4688c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Current values\n"); 4698c2ecf20Sopenharmony_ci break; 4708c2ecf20Sopenharmony_ci case 0x1: 4718c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Changeable values\n"); 4728c2ecf20Sopenharmony_ci break; 4738c2ecf20Sopenharmony_ci case 0x2: 4748c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Default values\n"); 4758c2ecf20Sopenharmony_ci break; 4768c2ecf20Sopenharmony_ci case 0x3: 4778c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Saves values\n"); 4788c2ecf20Sopenharmony_ci break; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci memset(ptr, 0, 8); 4828c2ecf20Sopenharmony_ci if (sense_6) { 4838c2ecf20Sopenharmony_ci ptr[2] = 0x00; // WP enable: 0x80 4848c2ecf20Sopenharmony_ci i = 4; 4858c2ecf20Sopenharmony_ci } else { 4868c2ecf20Sopenharmony_ci ptr[3] = 0x00; // WP enable: 0x80 4878c2ecf20Sopenharmony_ci i = 8; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci switch (page_code) { 4918c2ecf20Sopenharmony_ci default: 4928c2ecf20Sopenharmony_ci // vendor-specific mode 4938c2ecf20Sopenharmony_ci info->sense_key = 0x05; 4948c2ecf20Sopenharmony_ci info->sense_asc = 0x24; 4958c2ecf20Sopenharmony_ci info->sense_ascq = 0x00; 4968c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_FAILED; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci case 0x1: 4998c2ecf20Sopenharmony_ci memcpy(ptr + i, rw_err_page, sizeof(rw_err_page)); 5008c2ecf20Sopenharmony_ci i += sizeof(rw_err_page); 5018c2ecf20Sopenharmony_ci break; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci case 0x8: 5048c2ecf20Sopenharmony_ci memcpy(ptr + i, cache_page, sizeof(cache_page)); 5058c2ecf20Sopenharmony_ci i += sizeof(cache_page); 5068c2ecf20Sopenharmony_ci break; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci case 0x1B: 5098c2ecf20Sopenharmony_ci memcpy(ptr + i, rbac_page, sizeof(rbac_page)); 5108c2ecf20Sopenharmony_ci i += sizeof(rbac_page); 5118c2ecf20Sopenharmony_ci break; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci case 0x1C: 5148c2ecf20Sopenharmony_ci memcpy(ptr + i, timer_page, sizeof(timer_page)); 5158c2ecf20Sopenharmony_ci i += sizeof(timer_page); 5168c2ecf20Sopenharmony_ci break; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci case 0x3F: // retrieve all pages 5198c2ecf20Sopenharmony_ci memcpy(ptr + i, timer_page, sizeof(timer_page)); 5208c2ecf20Sopenharmony_ci i += sizeof(timer_page); 5218c2ecf20Sopenharmony_ci memcpy(ptr + i, rbac_page, sizeof(rbac_page)); 5228c2ecf20Sopenharmony_ci i += sizeof(rbac_page); 5238c2ecf20Sopenharmony_ci memcpy(ptr + i, cache_page, sizeof(cache_page)); 5248c2ecf20Sopenharmony_ci i += sizeof(cache_page); 5258c2ecf20Sopenharmony_ci memcpy(ptr + i, rw_err_page, sizeof(rw_err_page)); 5268c2ecf20Sopenharmony_ci i += sizeof(rw_err_page); 5278c2ecf20Sopenharmony_ci break; 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci if (sense_6) 5318c2ecf20Sopenharmony_ci ptr[0] = i - 1; 5328c2ecf20Sopenharmony_ci else 5338c2ecf20Sopenharmony_ci ((__be16 *) ptr)[0] = cpu_to_be16(i - 2); 5348c2ecf20Sopenharmony_ci usb_stor_set_xfer_buf(ptr, i, srb); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_cistatic void datafab_info_destructor(void *extra) 5408c2ecf20Sopenharmony_ci{ 5418c2ecf20Sopenharmony_ci // this routine is a placeholder... 5428c2ecf20Sopenharmony_ci // currently, we don't allocate any extra memory so we're okay 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci// Transport for the Datafab MDCFE-B 5478c2ecf20Sopenharmony_ci// 5488c2ecf20Sopenharmony_cistatic int datafab_transport(struct scsi_cmnd *srb, struct us_data *us) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci struct datafab_info *info; 5518c2ecf20Sopenharmony_ci int rc; 5528c2ecf20Sopenharmony_ci unsigned long block, blocks; 5538c2ecf20Sopenharmony_ci unsigned char *ptr = us->iobuf; 5548c2ecf20Sopenharmony_ci static unsigned char inquiry_reply[8] = { 5558c2ecf20Sopenharmony_ci 0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00 5568c2ecf20Sopenharmony_ci }; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci if (!us->extra) { 5598c2ecf20Sopenharmony_ci us->extra = kzalloc(sizeof(struct datafab_info), GFP_NOIO); 5608c2ecf20Sopenharmony_ci if (!us->extra) 5618c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci us->extra_destructor = datafab_info_destructor; 5648c2ecf20Sopenharmony_ci ((struct datafab_info *)us->extra)->lun = -1; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci info = (struct datafab_info *) (us->extra); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci if (srb->cmnd[0] == INQUIRY) { 5708c2ecf20Sopenharmony_ci usb_stor_dbg(us, "INQUIRY - Returning bogus response\n"); 5718c2ecf20Sopenharmony_ci memcpy(ptr, inquiry_reply, sizeof(inquiry_reply)); 5728c2ecf20Sopenharmony_ci fill_inquiry_response(us, ptr, 36); 5738c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci if (srb->cmnd[0] == READ_CAPACITY) { 5778c2ecf20Sopenharmony_ci info->ssize = 0x200; // hard coded 512 byte sectors as per ATA spec 5788c2ecf20Sopenharmony_ci rc = datafab_id_device(us, info); 5798c2ecf20Sopenharmony_ci if (rc != USB_STOR_TRANSPORT_GOOD) 5808c2ecf20Sopenharmony_ci return rc; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci usb_stor_dbg(us, "READ_CAPACITY: %ld sectors, %ld bytes per sector\n", 5838c2ecf20Sopenharmony_ci info->sectors, info->ssize); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci // build the reply 5868c2ecf20Sopenharmony_ci // we need the last sector, not the number of sectors 5878c2ecf20Sopenharmony_ci ((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1); 5888c2ecf20Sopenharmony_ci ((__be32 *) ptr)[1] = cpu_to_be32(info->ssize); 5898c2ecf20Sopenharmony_ci usb_stor_set_xfer_buf(ptr, 8, srb); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci if (srb->cmnd[0] == MODE_SELECT_10) { 5958c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Gah! MODE_SELECT_10\n"); 5968c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci // don't bother implementing READ_6 or WRITE_6. 6008c2ecf20Sopenharmony_ci // 6018c2ecf20Sopenharmony_ci if (srb->cmnd[0] == READ_10) { 6028c2ecf20Sopenharmony_ci block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | 6038c2ecf20Sopenharmony_ci ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci usb_stor_dbg(us, "READ_10: read block 0x%04lx count %ld\n", 6088c2ecf20Sopenharmony_ci block, blocks); 6098c2ecf20Sopenharmony_ci return datafab_read_data(us, info, block, blocks); 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci if (srb->cmnd[0] == READ_12) { 6138c2ecf20Sopenharmony_ci // we'll probably never see a READ_12 but we'll do it anyway... 6148c2ecf20Sopenharmony_ci // 6158c2ecf20Sopenharmony_ci block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | 6168c2ecf20Sopenharmony_ci ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | 6198c2ecf20Sopenharmony_ci ((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9])); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci usb_stor_dbg(us, "READ_12: read block 0x%04lx count %ld\n", 6228c2ecf20Sopenharmony_ci block, blocks); 6238c2ecf20Sopenharmony_ci return datafab_read_data(us, info, block, blocks); 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci if (srb->cmnd[0] == WRITE_10) { 6278c2ecf20Sopenharmony_ci block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | 6288c2ecf20Sopenharmony_ci ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci usb_stor_dbg(us, "WRITE_10: write block 0x%04lx count %ld\n", 6338c2ecf20Sopenharmony_ci block, blocks); 6348c2ecf20Sopenharmony_ci return datafab_write_data(us, info, block, blocks); 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci if (srb->cmnd[0] == WRITE_12) { 6388c2ecf20Sopenharmony_ci // we'll probably never see a WRITE_12 but we'll do it anyway... 6398c2ecf20Sopenharmony_ci // 6408c2ecf20Sopenharmony_ci block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | 6418c2ecf20Sopenharmony_ci ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | 6448c2ecf20Sopenharmony_ci ((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9])); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci usb_stor_dbg(us, "WRITE_12: write block 0x%04lx count %ld\n", 6478c2ecf20Sopenharmony_ci block, blocks); 6488c2ecf20Sopenharmony_ci return datafab_write_data(us, info, block, blocks); 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci if (srb->cmnd[0] == TEST_UNIT_READY) { 6528c2ecf20Sopenharmony_ci usb_stor_dbg(us, "TEST_UNIT_READY\n"); 6538c2ecf20Sopenharmony_ci return datafab_id_device(us, info); 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci if (srb->cmnd[0] == REQUEST_SENSE) { 6578c2ecf20Sopenharmony_ci usb_stor_dbg(us, "REQUEST_SENSE - Returning faked response\n"); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci // this response is pretty bogus right now. eventually if necessary 6608c2ecf20Sopenharmony_ci // we can set the correct sense data. so far though it hasn't been 6618c2ecf20Sopenharmony_ci // necessary 6628c2ecf20Sopenharmony_ci // 6638c2ecf20Sopenharmony_ci memset(ptr, 0, 18); 6648c2ecf20Sopenharmony_ci ptr[0] = 0xF0; 6658c2ecf20Sopenharmony_ci ptr[2] = info->sense_key; 6668c2ecf20Sopenharmony_ci ptr[7] = 11; 6678c2ecf20Sopenharmony_ci ptr[12] = info->sense_asc; 6688c2ecf20Sopenharmony_ci ptr[13] = info->sense_ascq; 6698c2ecf20Sopenharmony_ci usb_stor_set_xfer_buf(ptr, 18, srb); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci if (srb->cmnd[0] == MODE_SENSE) { 6758c2ecf20Sopenharmony_ci usb_stor_dbg(us, "MODE_SENSE_6 detected\n"); 6768c2ecf20Sopenharmony_ci return datafab_handle_mode_sense(us, srb, 1); 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci if (srb->cmnd[0] == MODE_SENSE_10) { 6808c2ecf20Sopenharmony_ci usb_stor_dbg(us, "MODE_SENSE_10 detected\n"); 6818c2ecf20Sopenharmony_ci return datafab_handle_mode_sense(us, srb, 0); 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { 6858c2ecf20Sopenharmony_ci /* 6868c2ecf20Sopenharmony_ci * sure. whatever. not like we can stop the user from 6878c2ecf20Sopenharmony_ci * popping the media out of the device (no locking doors, etc) 6888c2ecf20Sopenharmony_ci */ 6898c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci if (srb->cmnd[0] == START_STOP) { 6938c2ecf20Sopenharmony_ci /* 6948c2ecf20Sopenharmony_ci * this is used by sd.c'check_scsidisk_media_change to detect 6958c2ecf20Sopenharmony_ci * media change 6968c2ecf20Sopenharmony_ci */ 6978c2ecf20Sopenharmony_ci usb_stor_dbg(us, "START_STOP\n"); 6988c2ecf20Sopenharmony_ci /* 6998c2ecf20Sopenharmony_ci * the first datafab_id_device after a media change returns 7008c2ecf20Sopenharmony_ci * an error (determined experimentally) 7018c2ecf20Sopenharmony_ci */ 7028c2ecf20Sopenharmony_ci rc = datafab_id_device(us, info); 7038c2ecf20Sopenharmony_ci if (rc == USB_STOR_TRANSPORT_GOOD) { 7048c2ecf20Sopenharmony_ci info->sense_key = NO_SENSE; 7058c2ecf20Sopenharmony_ci srb->result = SUCCESS; 7068c2ecf20Sopenharmony_ci } else { 7078c2ecf20Sopenharmony_ci info->sense_key = UNIT_ATTENTION; 7088c2ecf20Sopenharmony_ci srb->result = SAM_STAT_CHECK_CONDITION; 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci return rc; 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Gah! Unknown command: %d (0x%x)\n", 7148c2ecf20Sopenharmony_ci srb->cmnd[0], srb->cmnd[0]); 7158c2ecf20Sopenharmony_ci info->sense_key = 0x05; 7168c2ecf20Sopenharmony_ci info->sense_asc = 0x20; 7178c2ecf20Sopenharmony_ci info->sense_ascq = 0x00; 7188c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_FAILED; 7198c2ecf20Sopenharmony_ci} 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_cistatic struct scsi_host_template datafab_host_template; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_cistatic int datafab_probe(struct usb_interface *intf, 7248c2ecf20Sopenharmony_ci const struct usb_device_id *id) 7258c2ecf20Sopenharmony_ci{ 7268c2ecf20Sopenharmony_ci struct us_data *us; 7278c2ecf20Sopenharmony_ci int result; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci result = usb_stor_probe1(&us, intf, id, 7308c2ecf20Sopenharmony_ci (id - datafab_usb_ids) + datafab_unusual_dev_list, 7318c2ecf20Sopenharmony_ci &datafab_host_template); 7328c2ecf20Sopenharmony_ci if (result) 7338c2ecf20Sopenharmony_ci return result; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci us->transport_name = "Datafab Bulk-Only"; 7368c2ecf20Sopenharmony_ci us->transport = datafab_transport; 7378c2ecf20Sopenharmony_ci us->transport_reset = usb_stor_Bulk_reset; 7388c2ecf20Sopenharmony_ci us->max_lun = 1; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci result = usb_stor_probe2(us); 7418c2ecf20Sopenharmony_ci return result; 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_cistatic struct usb_driver datafab_driver = { 7458c2ecf20Sopenharmony_ci .name = DRV_NAME, 7468c2ecf20Sopenharmony_ci .probe = datafab_probe, 7478c2ecf20Sopenharmony_ci .disconnect = usb_stor_disconnect, 7488c2ecf20Sopenharmony_ci .suspend = usb_stor_suspend, 7498c2ecf20Sopenharmony_ci .resume = usb_stor_resume, 7508c2ecf20Sopenharmony_ci .reset_resume = usb_stor_reset_resume, 7518c2ecf20Sopenharmony_ci .pre_reset = usb_stor_pre_reset, 7528c2ecf20Sopenharmony_ci .post_reset = usb_stor_post_reset, 7538c2ecf20Sopenharmony_ci .id_table = datafab_usb_ids, 7548c2ecf20Sopenharmony_ci .soft_unbind = 1, 7558c2ecf20Sopenharmony_ci .no_dynamic_id = 1, 7568c2ecf20Sopenharmony_ci}; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_cimodule_usb_stor_driver(datafab_driver, datafab_host_template, DRV_NAME); 759