cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

freecom.c (15497B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Driver for Freecom USB/IDE adaptor
      4 *
      5 * Freecom v0.1:
      6 *
      7 * First release
      8 *
      9 * Current development and maintenance by:
     10 *   (C) 2000 David Brown <usb-storage@davidb.org>
     11 *
     12 * This driver was developed with information provided in FREECOM's USB
     13 * Programmers Reference Guide.  For further information contact Freecom
     14 * (https://www.freecom.de/)
     15 */
     16
     17#include <linux/module.h>
     18#include <scsi/scsi.h>
     19#include <scsi/scsi_cmnd.h>
     20
     21#include "usb.h"
     22#include "transport.h"
     23#include "protocol.h"
     24#include "debug.h"
     25#include "scsiglue.h"
     26
     27#define DRV_NAME "ums-freecom"
     28
     29MODULE_DESCRIPTION("Driver for Freecom USB/IDE adaptor");
     30MODULE_AUTHOR("David Brown <usb-storage@davidb.org>");
     31MODULE_LICENSE("GPL");
     32MODULE_IMPORT_NS(USB_STORAGE);
     33
     34#ifdef CONFIG_USB_STORAGE_DEBUG
     35static void pdump(struct us_data *us, void *ibuffer, int length);
     36#endif
     37
     38/* Bits of HD_STATUS */
     39#define ERR_STAT		0x01
     40#define DRQ_STAT		0x08
     41
     42/* All of the outgoing packets are 64 bytes long. */
     43struct freecom_cb_wrap {
     44	u8    Type;		/* Command type. */
     45	u8    Timeout;		/* Timeout in seconds. */
     46	u8    Atapi[12];	/* An ATAPI packet. */
     47	u8    Filler[50];	/* Padding Data. */
     48};
     49
     50struct freecom_xfer_wrap {
     51	u8    Type;		/* Command type. */
     52	u8    Timeout;		/* Timeout in seconds. */
     53	__le32   Count;		/* Number of bytes to transfer. */
     54	u8    Pad[58];
     55} __attribute__ ((packed));
     56
     57struct freecom_ide_out {
     58	u8    Type;		/* Type + IDE register. */
     59	u8    Pad;
     60	__le16   Value;		/* Value to write. */
     61	u8    Pad2[60];
     62};
     63
     64struct freecom_ide_in {
     65	u8    Type;		/* Type | IDE register. */
     66	u8    Pad[63];
     67};
     68
     69struct freecom_status {
     70	u8    Status;
     71	u8    Reason;
     72	__le16   Count;
     73	u8    Pad[60];
     74};
     75
     76/*
     77 * Freecom stuffs the interrupt status in the INDEX_STAT bit of the ide
     78 * register.
     79 */
     80#define FCM_INT_STATUS		0x02 /* INDEX_STAT */
     81#define FCM_STATUS_BUSY		0x80
     82
     83/*
     84 * These are the packet types.  The low bit indicates that this command
     85 * should wait for an interrupt.
     86 */
     87#define FCM_PACKET_ATAPI	0x21
     88#define FCM_PACKET_STATUS	0x20
     89
     90/*
     91 * Receive data from the IDE interface.  The ATAPI packet has already
     92 * waited, so the data should be immediately available.
     93 */
     94#define FCM_PACKET_INPUT	0x81
     95
     96/* Send data to the IDE interface. */
     97#define FCM_PACKET_OUTPUT	0x01
     98
     99/*
    100 * Write a value to an ide register.  Or the ide register to write after
    101 * munging the address a bit.
    102 */
    103#define FCM_PACKET_IDE_WRITE	0x40
    104#define FCM_PACKET_IDE_READ	0xC0
    105
    106/* All packets (except for status) are 64 bytes long. */
    107#define FCM_PACKET_LENGTH		64
    108#define FCM_STATUS_PACKET_LENGTH	4
    109
    110static int init_freecom(struct us_data *us);
    111
    112
    113/*
    114 * The table of devices
    115 */
    116#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
    117		    vendorName, productName, useProtocol, useTransport, \
    118		    initFunction, flags) \
    119{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
    120  .driver_info = (flags) }
    121
    122static struct usb_device_id freecom_usb_ids[] = {
    123#	include "unusual_freecom.h"
    124	{ }		/* Terminating entry */
    125};
    126MODULE_DEVICE_TABLE(usb, freecom_usb_ids);
    127
    128#undef UNUSUAL_DEV
    129
    130/*
    131 * The flags table
    132 */
    133#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
    134		    vendor_name, product_name, use_protocol, use_transport, \
    135		    init_function, Flags) \
    136{ \
    137	.vendorName = vendor_name,	\
    138	.productName = product_name,	\
    139	.useProtocol = use_protocol,	\
    140	.useTransport = use_transport,	\
    141	.initFunction = init_function,	\
    142}
    143
    144static struct us_unusual_dev freecom_unusual_dev_list[] = {
    145#	include "unusual_freecom.h"
    146	{ }		/* Terminating entry */
    147};
    148
    149#undef UNUSUAL_DEV
    150
    151static int
    152freecom_readdata (struct scsi_cmnd *srb, struct us_data *us,
    153		unsigned int ipipe, unsigned int opipe, int count)
    154{
    155	struct freecom_xfer_wrap *fxfr =
    156		(struct freecom_xfer_wrap *) us->iobuf;
    157	int result;
    158
    159	fxfr->Type = FCM_PACKET_INPUT | 0x00;
    160	fxfr->Timeout = 0;    /* Short timeout for debugging. */
    161	fxfr->Count = cpu_to_le32 (count);
    162	memset (fxfr->Pad, 0, sizeof (fxfr->Pad));
    163
    164	usb_stor_dbg(us, "Read data Freecom! (c=%d)\n", count);
    165
    166	/* Issue the transfer command. */
    167	result = usb_stor_bulk_transfer_buf (us, opipe, fxfr,
    168			FCM_PACKET_LENGTH, NULL);
    169	if (result != USB_STOR_XFER_GOOD) {
    170		usb_stor_dbg(us, "Freecom readdata transport error\n");
    171		return USB_STOR_TRANSPORT_ERROR;
    172	}
    173
    174	/* Now transfer all of our blocks. */
    175	usb_stor_dbg(us, "Start of read\n");
    176	result = usb_stor_bulk_srb(us, ipipe, srb);
    177	usb_stor_dbg(us, "freecom_readdata done!\n");
    178
    179	if (result > USB_STOR_XFER_SHORT)
    180		return USB_STOR_TRANSPORT_ERROR;
    181	return USB_STOR_TRANSPORT_GOOD;
    182}
    183
    184static int
    185freecom_writedata (struct scsi_cmnd *srb, struct us_data *us,
    186		int unsigned ipipe, unsigned int opipe, int count)
    187{
    188	struct freecom_xfer_wrap *fxfr =
    189		(struct freecom_xfer_wrap *) us->iobuf;
    190	int result;
    191
    192	fxfr->Type = FCM_PACKET_OUTPUT | 0x00;
    193	fxfr->Timeout = 0;    /* Short timeout for debugging. */
    194	fxfr->Count = cpu_to_le32 (count);
    195	memset (fxfr->Pad, 0, sizeof (fxfr->Pad));
    196
    197	usb_stor_dbg(us, "Write data Freecom! (c=%d)\n", count);
    198
    199	/* Issue the transfer command. */
    200	result = usb_stor_bulk_transfer_buf (us, opipe, fxfr,
    201			FCM_PACKET_LENGTH, NULL);
    202	if (result != USB_STOR_XFER_GOOD) {
    203		usb_stor_dbg(us, "Freecom writedata transport error\n");
    204		return USB_STOR_TRANSPORT_ERROR;
    205	}
    206
    207	/* Now transfer all of our blocks. */
    208	usb_stor_dbg(us, "Start of write\n");
    209	result = usb_stor_bulk_srb(us, opipe, srb);
    210
    211	usb_stor_dbg(us, "freecom_writedata done!\n");
    212	if (result > USB_STOR_XFER_SHORT)
    213		return USB_STOR_TRANSPORT_ERROR;
    214	return USB_STOR_TRANSPORT_GOOD;
    215}
    216
    217/*
    218 * Transport for the Freecom USB/IDE adaptor.
    219 *
    220 */
    221static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
    222{
    223	struct freecom_cb_wrap *fcb;
    224	struct freecom_status  *fst;
    225	unsigned int ipipe, opipe;		/* We need both pipes. */
    226	int result;
    227	unsigned int partial;
    228	int length;
    229
    230	fcb = (struct freecom_cb_wrap *) us->iobuf;
    231	fst = (struct freecom_status *) us->iobuf;
    232
    233	usb_stor_dbg(us, "Freecom TRANSPORT STARTED\n");
    234
    235	/* Get handles for both transports. */
    236	opipe = us->send_bulk_pipe;
    237	ipipe = us->recv_bulk_pipe;
    238
    239	/* The ATAPI Command always goes out first. */
    240	fcb->Type = FCM_PACKET_ATAPI | 0x00;
    241	fcb->Timeout = 0;
    242	memcpy (fcb->Atapi, srb->cmnd, 12);
    243	memset (fcb->Filler, 0, sizeof (fcb->Filler));
    244
    245	US_DEBUG(pdump(us, srb->cmnd, 12));
    246
    247	/* Send it out. */
    248	result = usb_stor_bulk_transfer_buf (us, opipe, fcb,
    249			FCM_PACKET_LENGTH, NULL);
    250
    251	/*
    252	 * The Freecom device will only fail if there is something wrong in
    253	 * USB land.  It returns the status in its own registers, which
    254	 * come back in the bulk pipe.
    255	 */
    256	if (result != USB_STOR_XFER_GOOD) {
    257		usb_stor_dbg(us, "freecom transport error\n");
    258		return USB_STOR_TRANSPORT_ERROR;
    259	}
    260
    261	/*
    262	 * There are times we can optimize out this status read, but it
    263	 * doesn't hurt us to always do it now.
    264	 */
    265	result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
    266			FCM_STATUS_PACKET_LENGTH, &partial);
    267	usb_stor_dbg(us, "foo Status result %d %u\n", result, partial);
    268	if (result != USB_STOR_XFER_GOOD)
    269		return USB_STOR_TRANSPORT_ERROR;
    270
    271	US_DEBUG(pdump(us, (void *)fst, partial));
    272
    273	/*
    274	 * The firmware will time-out commands after 20 seconds. Some commands
    275	 * can legitimately take longer than this, so we use a different
    276	 * command that only waits for the interrupt and then sends status,
    277	 * without having to send a new ATAPI command to the device.
    278	 *
    279	 * NOTE: There is some indication that a data transfer after a timeout
    280	 * may not work, but that is a condition that should never happen.
    281	 */
    282	while (fst->Status & FCM_STATUS_BUSY) {
    283		usb_stor_dbg(us, "20 second USB/ATAPI bridge TIMEOUT occurred!\n");
    284		usb_stor_dbg(us, "fst->Status is %x\n", fst->Status);
    285
    286		/* Get the status again */
    287		fcb->Type = FCM_PACKET_STATUS;
    288		fcb->Timeout = 0;
    289		memset (fcb->Atapi, 0, sizeof(fcb->Atapi));
    290		memset (fcb->Filler, 0, sizeof (fcb->Filler));
    291
    292		/* Send it out. */
    293		result = usb_stor_bulk_transfer_buf (us, opipe, fcb,
    294				FCM_PACKET_LENGTH, NULL);
    295
    296		/*
    297		 * The Freecom device will only fail if there is something
    298		 * wrong in USB land.  It returns the status in its own
    299		 * registers, which come back in the bulk pipe.
    300		 */
    301		if (result != USB_STOR_XFER_GOOD) {
    302			usb_stor_dbg(us, "freecom transport error\n");
    303			return USB_STOR_TRANSPORT_ERROR;
    304		}
    305
    306		/* get the data */
    307		result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
    308				FCM_STATUS_PACKET_LENGTH, &partial);
    309
    310		usb_stor_dbg(us, "bar Status result %d %u\n", result, partial);
    311		if (result != USB_STOR_XFER_GOOD)
    312			return USB_STOR_TRANSPORT_ERROR;
    313
    314		US_DEBUG(pdump(us, (void *)fst, partial));
    315	}
    316
    317	if (partial != 4)
    318		return USB_STOR_TRANSPORT_ERROR;
    319	if ((fst->Status & 1) != 0) {
    320		usb_stor_dbg(us, "operation failed\n");
    321		return USB_STOR_TRANSPORT_FAILED;
    322	}
    323
    324	/*
    325	 * The device might not have as much data available as we
    326	 * requested.  If you ask for more than the device has, this reads
    327	 * and such will hang.
    328	 */
    329	usb_stor_dbg(us, "Device indicates that it has %d bytes available\n",
    330		     le16_to_cpu(fst->Count));
    331	usb_stor_dbg(us, "SCSI requested %d\n", scsi_bufflen(srb));
    332
    333	/* Find the length we desire to read. */
    334	switch (srb->cmnd[0]) {
    335	case INQUIRY:
    336	case REQUEST_SENSE:	/* 16 or 18 bytes? spec says 18, lots of devices only have 16 */
    337	case MODE_SENSE:
    338	case MODE_SENSE_10:
    339		length = le16_to_cpu(fst->Count);
    340		break;
    341	default:
    342		length = scsi_bufflen(srb);
    343	}
    344
    345	/* verify that this amount is legal */
    346	if (length > scsi_bufflen(srb)) {
    347		length = scsi_bufflen(srb);
    348		usb_stor_dbg(us, "Truncating request to match buffer length: %d\n",
    349			     length);
    350	}
    351
    352	/*
    353	 * What we do now depends on what direction the data is supposed to
    354	 * move in.
    355	 */
    356
    357	switch (us->srb->sc_data_direction) {
    358	case DMA_FROM_DEVICE:
    359		/* catch bogus "read 0 length" case */
    360		if (!length)
    361			break;
    362		/*
    363		 * Make sure that the status indicates that the device
    364		 * wants data as well.
    365		 */
    366		if ((fst->Status & DRQ_STAT) == 0 || (fst->Reason & 3) != 2) {
    367			usb_stor_dbg(us, "SCSI wants data, drive doesn't have any\n");
    368			return USB_STOR_TRANSPORT_FAILED;
    369		}
    370		result = freecom_readdata (srb, us, ipipe, opipe, length);
    371		if (result != USB_STOR_TRANSPORT_GOOD)
    372			return result;
    373
    374		usb_stor_dbg(us, "Waiting for status\n");
    375		result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
    376				FCM_PACKET_LENGTH, &partial);
    377		US_DEBUG(pdump(us, (void *)fst, partial));
    378
    379		if (partial != 4 || result > USB_STOR_XFER_SHORT)
    380			return USB_STOR_TRANSPORT_ERROR;
    381		if ((fst->Status & ERR_STAT) != 0) {
    382			usb_stor_dbg(us, "operation failed\n");
    383			return USB_STOR_TRANSPORT_FAILED;
    384		}
    385		if ((fst->Reason & 3) != 3) {
    386			usb_stor_dbg(us, "Drive seems still hungry\n");
    387			return USB_STOR_TRANSPORT_FAILED;
    388		}
    389		usb_stor_dbg(us, "Transfer happy\n");
    390		break;
    391
    392	case DMA_TO_DEVICE:
    393		/* catch bogus "write 0 length" case */
    394		if (!length)
    395			break;
    396		/*
    397		 * Make sure the status indicates that the device wants to
    398		 * send us data.
    399		 */
    400		/* !!IMPLEMENT!! */
    401		result = freecom_writedata (srb, us, ipipe, opipe, length);
    402		if (result != USB_STOR_TRANSPORT_GOOD)
    403			return result;
    404
    405		usb_stor_dbg(us, "Waiting for status\n");
    406		result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
    407				FCM_PACKET_LENGTH, &partial);
    408
    409		if (partial != 4 || result > USB_STOR_XFER_SHORT)
    410			return USB_STOR_TRANSPORT_ERROR;
    411		if ((fst->Status & ERR_STAT) != 0) {
    412			usb_stor_dbg(us, "operation failed\n");
    413			return USB_STOR_TRANSPORT_FAILED;
    414		}
    415		if ((fst->Reason & 3) != 3) {
    416			usb_stor_dbg(us, "Drive seems still hungry\n");
    417			return USB_STOR_TRANSPORT_FAILED;
    418		}
    419
    420		usb_stor_dbg(us, "Transfer happy\n");
    421		break;
    422
    423
    424	case DMA_NONE:
    425		/* Easy, do nothing. */
    426		break;
    427
    428	default:
    429		/* should never hit here -- filtered in usb.c */
    430		usb_stor_dbg(us, "freecom unimplemented direction: %d\n",
    431			     us->srb->sc_data_direction);
    432		/* Return fail, SCSI seems to handle this better. */
    433		return USB_STOR_TRANSPORT_FAILED;
    434	}
    435
    436	return USB_STOR_TRANSPORT_GOOD;
    437}
    438
    439static int init_freecom(struct us_data *us)
    440{
    441	int result;
    442	char *buffer = us->iobuf;
    443
    444	/*
    445	 * The DMA-mapped I/O buffer is 64 bytes long, just right for
    446	 * all our packets.  No need to allocate any extra buffer space.
    447	 */
    448
    449	result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
    450			0x4c, 0xc0, 0x4346, 0x0, buffer, 0x20, 3*HZ);
    451	buffer[32] = '\0';
    452	usb_stor_dbg(us, "String returned from FC init is: %s\n", buffer);
    453
    454	/*
    455	 * Special thanks to the people at Freecom for providing me with
    456	 * this "magic sequence", which they use in their Windows and MacOS
    457	 * drivers to make sure that all the attached perhiperals are
    458	 * properly reset.
    459	 */
    460
    461	/* send reset */
    462	result = usb_stor_control_msg(us, us->send_ctrl_pipe,
    463			0x4d, 0x40, 0x24d8, 0x0, NULL, 0x0, 3*HZ);
    464	usb_stor_dbg(us, "result from activate reset is %d\n", result);
    465
    466	/* wait 250ms */
    467	msleep(250);
    468
    469	/* clear reset */
    470	result = usb_stor_control_msg(us, us->send_ctrl_pipe,
    471			0x4d, 0x40, 0x24f8, 0x0, NULL, 0x0, 3*HZ);
    472	usb_stor_dbg(us, "result from clear reset is %d\n", result);
    473
    474	/* wait 3 seconds */
    475	msleep(3 * 1000);
    476
    477	return USB_STOR_TRANSPORT_GOOD;
    478}
    479
    480static int usb_stor_freecom_reset(struct us_data *us)
    481{
    482	printk (KERN_CRIT "freecom reset called\n");
    483
    484	/* We don't really have this feature. */
    485	return FAILED;
    486}
    487
    488#ifdef CONFIG_USB_STORAGE_DEBUG
    489static void pdump(struct us_data *us, void *ibuffer, int length)
    490{
    491	static char line[80];
    492	int offset = 0;
    493	unsigned char *buffer = (unsigned char *) ibuffer;
    494	int i, j;
    495	int from, base;
    496
    497	offset = 0;
    498	for (i = 0; i < length; i++) {
    499		if ((i & 15) == 0) {
    500			if (i > 0) {
    501				offset += sprintf (line+offset, " - ");
    502				for (j = i - 16; j < i; j++) {
    503					if (buffer[j] >= 32 && buffer[j] <= 126)
    504						line[offset++] = buffer[j];
    505					else
    506						line[offset++] = '.';
    507				}
    508				line[offset] = 0;
    509				usb_stor_dbg(us, "%s\n", line);
    510				offset = 0;
    511			}
    512			offset += sprintf (line+offset, "%08x:", i);
    513		} else if ((i & 7) == 0) {
    514			offset += sprintf (line+offset, " -");
    515		}
    516		offset += sprintf (line+offset, " %02x", buffer[i] & 0xff);
    517	}
    518
    519	/* Add the last "chunk" of data. */
    520	from = (length - 1) % 16;
    521	base = ((length - 1) / 16) * 16;
    522
    523	for (i = from + 1; i < 16; i++)
    524		offset += sprintf (line+offset, "   ");
    525	if (from < 8)
    526		offset += sprintf (line+offset, "  ");
    527	offset += sprintf (line+offset, " - ");
    528
    529	for (i = 0; i <= from; i++) {
    530		if (buffer[base+i] >= 32 && buffer[base+i] <= 126)
    531			line[offset++] = buffer[base+i];
    532		else
    533			line[offset++] = '.';
    534	}
    535	line[offset] = 0;
    536	usb_stor_dbg(us, "%s\n", line);
    537	offset = 0;
    538}
    539#endif
    540
    541static struct scsi_host_template freecom_host_template;
    542
    543static int freecom_probe(struct usb_interface *intf,
    544			 const struct usb_device_id *id)
    545{
    546	struct us_data *us;
    547	int result;
    548
    549	result = usb_stor_probe1(&us, intf, id,
    550			(id - freecom_usb_ids) + freecom_unusual_dev_list,
    551			&freecom_host_template);
    552	if (result)
    553		return result;
    554
    555	us->transport_name = "Freecom";
    556	us->transport = freecom_transport;
    557	us->transport_reset = usb_stor_freecom_reset;
    558	us->max_lun = 0;
    559
    560	result = usb_stor_probe2(us);
    561	return result;
    562}
    563
    564static struct usb_driver freecom_driver = {
    565	.name =		DRV_NAME,
    566	.probe =	freecom_probe,
    567	.disconnect =	usb_stor_disconnect,
    568	.suspend =	usb_stor_suspend,
    569	.resume =	usb_stor_resume,
    570	.reset_resume =	usb_stor_reset_resume,
    571	.pre_reset =	usb_stor_pre_reset,
    572	.post_reset =	usb_stor_post_reset,
    573	.id_table =	freecom_usb_ids,
    574	.soft_unbind =	1,
    575	.no_dynamic_id = 1,
    576};
    577
    578module_usb_stor_driver(freecom_driver, freecom_host_template, DRV_NAME);