ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / usb / storage / freecom.c
1 /* Driver for Freecom USB/IDE adaptor
2  *
3  * $Id: freecom.c,v 1.22 2002/04/22 03:39:43 mdharm Exp $
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 program is free software; you can redistribute it and/or modify it
13  * under the terms of the GNU General Public License as published by the
14  * Free Software Foundation; either version 2, or (at your option) any
15  * later version.
16  *
17  * This program is distributed in the hope that it will be useful, but
18  * WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License along
23  * with this program; if not, write to the Free Software Foundation, Inc.,
24  * 675 Mass Ave, Cambridge, MA 02139, USA.
25  *
26  * This driver was developed with information provided in FREECOM's USB
27  * Programmers Reference Guide.  For further information contact Freecom
28  * (http://www.freecom.de/)
29  */
30
31 #include <linux/config.h>
32 #include "transport.h"
33 #include "protocol.h"
34 #include "usb.h"
35 #include "debug.h"
36 #include "freecom.h"
37 #include "linux/hdreg.h"
38
39 #ifdef CONFIG_USB_STORAGE_DEBUG
40 static void pdump (void *, int);
41 #endif
42
43 /* Bits of HD_STATUS */
44 #define ERR_STAT                0x01
45 #define DRQ_STAT                0x08
46
47 /* All of the outgoing packets are 64 bytes long. */
48 struct freecom_cb_wrap {
49         u8    Type;             /* Command type. */
50         u8    Timeout;          /* Timeout in seconds. */
51         u8    Atapi[12];        /* An ATAPI packet. */
52         u8    Filler[50];       /* Padding Data. */
53 };
54
55 struct freecom_xfer_wrap {
56         u8    Type;             /* Command type. */
57         u8    Timeout;          /* Timeout in seconds. */
58         u32   Count;            /* Number of bytes to transfer. */
59         u8    Pad[58];
60 } __attribute__ ((packed));
61
62 struct freecom_ide_out {
63         u8    Type;             /* Type + IDE register. */
64         u8    Pad;
65         u16   Value;            /* Value to write. */
66         u8    Pad2[60];
67 };
68
69 struct freecom_ide_in {
70         u8    Type;             /* Type | IDE register. */
71         u8    Pad[63];
72 };
73
74 struct freecom_status {
75         u8    Status;
76         u8    Reason;
77         u16   Count;
78         u8    Pad[60];
79 };
80
81 /* Freecom stuffs the interrupt status in the INDEX_STAT bit of the ide
82  * register. */
83 #define FCM_INT_STATUS          0x02 /* INDEX_STAT */
84 #define FCM_STATUS_BUSY         0x80
85
86 /* These are the packet types.  The low bit indicates that this command
87  * should wait for an interrupt. */
88 #define FCM_PACKET_ATAPI        0x21
89 #define FCM_PACKET_STATUS       0x20
90
91 /* Receive data from the IDE interface.  The ATAPI packet has already
92  * waited, so the data should be immediately available. */
93 #define FCM_PACKET_INPUT        0x81
94
95 /* Send data to the IDE interface. */
96 #define FCM_PACKET_OUTPUT       0x01
97
98 /* Write a value to an ide register.  Or the ide register to write after
99  * munging the address a bit. */
100 #define FCM_PACKET_IDE_WRITE    0x40
101 #define FCM_PACKET_IDE_READ     0xC0
102
103 /* All packets (except for status) are 64 bytes long. */
104 #define FCM_PACKET_LENGTH               64
105 #define FCM_STATUS_PACKET_LENGTH        4
106
107 static int
108 freecom_readdata (Scsi_Cmnd *srb, struct us_data *us,
109                 unsigned int ipipe, unsigned int opipe, int count)
110 {
111         struct freecom_xfer_wrap *fxfr =
112                 (struct freecom_xfer_wrap *) us->iobuf;
113         int result;
114
115         fxfr->Type = FCM_PACKET_INPUT | 0x00;
116         fxfr->Timeout = 0;    /* Short timeout for debugging. */
117         fxfr->Count = cpu_to_le32 (count);
118         memset (fxfr->Pad, 0, sizeof (fxfr->Pad));
119
120         US_DEBUGP("Read data Freecom! (c=%d)\n", count);
121
122         /* Issue the transfer command. */
123         result = usb_stor_bulk_transfer_buf (us, opipe, fxfr,
124                         FCM_PACKET_LENGTH, NULL);
125         if (result != USB_STOR_XFER_GOOD) {
126                 US_DEBUGP ("Freecom readdata transport error\n");
127                 return USB_STOR_TRANSPORT_ERROR;
128         }
129
130         /* Now transfer all of our blocks. */
131         US_DEBUGP("Start of read\n");
132         result = usb_stor_bulk_transfer_sg(us, ipipe, srb->request_buffer,
133                         count, srb->use_sg, &srb->resid);
134         US_DEBUGP("freecom_readdata done!\n");
135
136         if (result > USB_STOR_XFER_SHORT)
137                 return USB_STOR_TRANSPORT_ERROR;
138         return USB_STOR_TRANSPORT_GOOD;
139 }
140
141 static int
142 freecom_writedata (Scsi_Cmnd *srb, struct us_data *us,
143                 int unsigned ipipe, unsigned int opipe, int count)
144 {
145         struct freecom_xfer_wrap *fxfr =
146                 (struct freecom_xfer_wrap *) us->iobuf;
147         int result;
148
149         fxfr->Type = FCM_PACKET_OUTPUT | 0x00;
150         fxfr->Timeout = 0;    /* Short timeout for debugging. */
151         fxfr->Count = cpu_to_le32 (count);
152         memset (fxfr->Pad, 0, sizeof (fxfr->Pad));
153
154         US_DEBUGP("Write data Freecom! (c=%d)\n", count);
155
156         /* Issue the transfer command. */
157         result = usb_stor_bulk_transfer_buf (us, opipe, fxfr,
158                         FCM_PACKET_LENGTH, NULL);
159         if (result != USB_STOR_XFER_GOOD) {
160                 US_DEBUGP ("Freecom writedata transport error\n");
161                 return USB_STOR_TRANSPORT_ERROR;
162         }
163
164         /* Now transfer all of our blocks. */
165         US_DEBUGP("Start of write\n");
166         result = usb_stor_bulk_transfer_sg(us, opipe, srb->request_buffer,
167                         count, srb->use_sg, &srb->resid);
168
169         US_DEBUGP("freecom_writedata done!\n");
170         if (result > USB_STOR_XFER_SHORT)
171                 return USB_STOR_TRANSPORT_ERROR;
172         return USB_STOR_TRANSPORT_GOOD;
173 }
174
175 /*
176  * Transport for the Freecom USB/IDE adaptor.
177  *
178  */
179 int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
180 {
181         struct freecom_cb_wrap *fcb;
182         struct freecom_status  *fst;
183         unsigned int ipipe, opipe;              /* We need both pipes. */
184         int result;
185         unsigned int partial;
186         int length;
187
188         fcb = (struct freecom_cb_wrap *) us->iobuf;
189         fst = (struct freecom_status *) us->iobuf;
190
191         US_DEBUGP("Freecom TRANSPORT STARTED\n");
192
193         /* Get handles for both transports. */
194         opipe = us->send_bulk_pipe;
195         ipipe = us->recv_bulk_pipe;
196
197         /* The ATAPI Command always goes out first. */
198         fcb->Type = FCM_PACKET_ATAPI | 0x00;
199         fcb->Timeout = 0;
200         memcpy (fcb->Atapi, srb->cmnd, 12);
201         memset (fcb->Filler, 0, sizeof (fcb->Filler));
202
203         US_DEBUG(pdump (srb->cmnd, 12));
204
205         /* Send it out. */
206         result = usb_stor_bulk_transfer_buf (us, opipe, fcb,
207                         FCM_PACKET_LENGTH, NULL);
208
209         /* The Freecom device will only fail if there is something wrong in
210          * USB land.  It returns the status in its own registers, which
211          * come back in the bulk pipe. */
212         if (result != USB_STOR_XFER_GOOD) {
213                 US_DEBUGP ("freecom transport error\n");
214                 return USB_STOR_TRANSPORT_ERROR;
215         }
216
217         /* There are times we can optimize out this status read, but it
218          * doesn't hurt us to always do it now. */
219         result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
220                         FCM_STATUS_PACKET_LENGTH, &partial);
221         US_DEBUGP("foo Status result %d %u\n", result, partial);
222         if (result != USB_STOR_XFER_GOOD)
223                 return USB_STOR_TRANSPORT_ERROR;
224
225         US_DEBUG(pdump ((void *) fst, partial));
226
227         /* The firmware will time-out commands after 20 seconds. Some commands
228          * can legitimately take longer than this, so we use a different
229          * command that only waits for the interrupt and then sends status,
230          * without having to send a new ATAPI command to the device. 
231          *
232          * NOTE: There is some indication that a data transfer after a timeout
233          * may not work, but that is a condition that should never happen.
234          */
235         while (fst->Status & FCM_STATUS_BUSY) {
236                 US_DEBUGP("20 second USB/ATAPI bridge TIMEOUT occurred!\n");
237                 US_DEBUGP("fst->Status is %x\n", fst->Status);
238
239                 /* Get the status again */
240                 fcb->Type = FCM_PACKET_STATUS;
241                 fcb->Timeout = 0;
242                 memset (fcb->Atapi, 0, sizeof(fcb->Atapi));
243                 memset (fcb->Filler, 0, sizeof (fcb->Filler));
244
245                 /* Send it out. */
246                 result = usb_stor_bulk_transfer_buf (us, opipe, fcb,
247                                 FCM_PACKET_LENGTH, NULL);
248
249                 /* The Freecom device will only fail if there is something
250                  * wrong in USB land.  It returns the status in its own
251                  * registers, which come back in the bulk pipe.
252                  */
253                 if (result != USB_STOR_XFER_GOOD) {
254                         US_DEBUGP ("freecom transport error\n");
255                         return USB_STOR_TRANSPORT_ERROR;
256                 }
257
258                 /* get the data */
259                 result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
260                                 FCM_STATUS_PACKET_LENGTH, &partial);
261
262                 US_DEBUGP("bar Status result %d %u\n", result, partial);
263                 if (result != USB_STOR_XFER_GOOD)
264                         return USB_STOR_TRANSPORT_ERROR;
265
266                 US_DEBUG(pdump ((void *) fst, partial));
267         }
268
269         if (partial != 4)
270                 return USB_STOR_TRANSPORT_ERROR;
271         if ((fst->Status & 1) != 0) {
272                 US_DEBUGP("operation failed\n");
273                 return USB_STOR_TRANSPORT_FAILED;
274         }
275
276         /* The device might not have as much data available as we
277          * requested.  If you ask for more than the device has, this reads
278          * and such will hang. */
279         US_DEBUGP("Device indicates that it has %d bytes available\n",
280                         le16_to_cpu (fst->Count));
281         US_DEBUGP("SCSI requested %d\n", srb->request_bufflen);
282
283         /* Find the length we desire to read. */
284         switch (srb->cmnd[0]) {
285                 case INQUIRY:
286                 case REQUEST_SENSE:             /* 16 or 18 bytes? spec says 18, lots of devices only have 16 */
287                 case MODE_SENSE:
288                 case MODE_SENSE_10:
289                         length = fst->Count;
290                         break;
291                 default:
292                         length = srb->request_bufflen;
293         }
294
295         /* verify that this amount is legal */
296         if (length > srb->request_bufflen) {
297                 length = srb->request_bufflen;
298                 US_DEBUGP("Truncating request to match buffer length: %d\n", length);
299         }
300
301         /* What we do now depends on what direction the data is supposed to
302          * move in. */
303
304         switch (us->srb->sc_data_direction) {
305         case SCSI_DATA_READ:
306                 /* catch bogus "read 0 length" case */
307                 if (!length)
308                         break;
309                 /* Make sure that the status indicates that the device
310                  * wants data as well. */
311                 if ((fst->Status & DRQ_STAT) == 0 || (fst->Reason & 3) != 2) {
312                         US_DEBUGP("SCSI wants data, drive doesn't have any\n");
313                         return USB_STOR_TRANSPORT_FAILED;
314                 }
315                 result = freecom_readdata (srb, us, ipipe, opipe, length);
316                 if (result != USB_STOR_TRANSPORT_GOOD)
317                         return result;
318
319                 US_DEBUGP("FCM: Waiting for status\n");
320                 result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
321                                 FCM_PACKET_LENGTH, &partial);
322                 US_DEBUG(pdump ((void *) fst, partial));
323
324                 if (partial != 4 || result > USB_STOR_XFER_SHORT)
325                         return USB_STOR_TRANSPORT_ERROR;
326                 if ((fst->Status & ERR_STAT) != 0) {
327                         US_DEBUGP("operation failed\n");
328                         return USB_STOR_TRANSPORT_FAILED;
329                 }
330                 if ((fst->Reason & 3) != 3) {
331                         US_DEBUGP("Drive seems still hungry\n");
332                         return USB_STOR_TRANSPORT_FAILED;
333                 }
334                 US_DEBUGP("Transfer happy\n");
335                 break;
336
337         case SCSI_DATA_WRITE:
338                 /* catch bogus "write 0 length" case */
339                 if (!length)
340                         break;
341                 /* Make sure the status indicates that the device wants to
342                  * send us data. */
343                 /* !!IMPLEMENT!! */
344                 result = freecom_writedata (srb, us, ipipe, opipe, length);
345                 if (result != USB_STOR_TRANSPORT_GOOD)
346                         return result;
347
348                 US_DEBUGP("FCM: Waiting for status\n");
349                 result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
350                                 FCM_PACKET_LENGTH, &partial);
351
352                 if (partial != 4 || result > USB_STOR_XFER_SHORT)
353                         return USB_STOR_TRANSPORT_ERROR;
354                 if ((fst->Status & ERR_STAT) != 0) {
355                         US_DEBUGP("operation failed\n");
356                         return USB_STOR_TRANSPORT_FAILED;
357                 }
358                 if ((fst->Reason & 3) != 3) {
359                         US_DEBUGP("Drive seems still hungry\n");
360                         return USB_STOR_TRANSPORT_FAILED;
361                 }
362
363                 US_DEBUGP("Transfer happy\n");
364                 break;
365
366
367         case SCSI_DATA_NONE:
368                 /* Easy, do nothing. */
369                 break;
370
371         default:
372                 /* should never hit here -- filtered in usb.c */
373                 US_DEBUGP ("freecom unimplemented direction: %d\n",
374                                 us->srb->sc_data_direction);
375                 // Return fail, SCSI seems to handle this better.
376                 return USB_STOR_TRANSPORT_FAILED;
377                 break;
378         }
379
380         return USB_STOR_TRANSPORT_GOOD;
381 }
382
383 int
384 freecom_init (struct us_data *us)
385 {
386         int result;
387         char *buffer = us->iobuf;
388
389         /* The DMA-mapped I/O buffer is 64 bytes long, just right for
390          * all our packets.  No need to allocate any extra buffer space.
391          */
392
393         result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
394                         0x4c, 0xc0, 0x4346, 0x0, buffer, 0x20, 3*HZ);
395         buffer[32] = '\0';
396         US_DEBUGP("String returned from FC init is: %s\n", buffer);
397
398         /* Special thanks to the people at Freecom for providing me with
399          * this "magic sequence", which they use in their Windows and MacOS
400          * drivers to make sure that all the attached perhiperals are
401          * properly reset.
402          */
403
404         /* send reset */
405         result = usb_stor_control_msg(us, us->send_ctrl_pipe,
406                         0x4d, 0x40, 0x24d8, 0x0, NULL, 0x0, 3*HZ);
407         US_DEBUGP("result from activate reset is %d\n", result);
408
409         /* wait 250ms */
410         mdelay(250);
411
412         /* clear reset */
413         result = usb_stor_control_msg(us, us->send_ctrl_pipe,
414                         0x4d, 0x40, 0x24f8, 0x0, NULL, 0x0, 3*HZ);
415         US_DEBUGP("result from clear reset is %d\n", result);
416
417         /* wait 3 seconds */
418         mdelay(3 * 1000);
419
420         return USB_STOR_TRANSPORT_GOOD;
421 }
422
423 int usb_stor_freecom_reset(struct us_data *us)
424 {
425         printk (KERN_CRIT "freecom reset called\n");
426
427         /* We don't really have this feature. */
428         return FAILED;
429 }
430
431 #ifdef CONFIG_USB_STORAGE_DEBUG
432 static void pdump (void *ibuffer, int length)
433 {
434         static char line[80];
435         int offset = 0;
436         unsigned char *buffer = (unsigned char *) ibuffer;
437         int i, j;
438         int from, base;
439
440         offset = 0;
441         for (i = 0; i < length; i++) {
442                 if ((i & 15) == 0) {
443                         if (i > 0) {
444                                 offset += sprintf (line+offset, " - ");
445                                 for (j = i - 16; j < i; j++) {
446                                         if (buffer[j] >= 32 && buffer[j] <= 126)
447                                                 line[offset++] = buffer[j];
448                                         else
449                                                 line[offset++] = '.';
450                                 }
451                                 line[offset] = 0;
452                                 US_DEBUGP("%s\n", line);
453                                 offset = 0;
454                         }
455                         offset += sprintf (line+offset, "%08x:", i);
456                 }
457                 else if ((i & 7) == 0) {
458                         offset += sprintf (line+offset, " -");
459                 }
460                 offset += sprintf (line+offset, " %02x", buffer[i] & 0xff);
461         }
462
463         /* Add the last "chunk" of data. */
464         from = (length - 1) % 16;
465         base = ((length - 1) / 16) * 16;
466
467         for (i = from + 1; i < 16; i++)
468                 offset += sprintf (line+offset, "   ");
469         if (from < 8)
470                 offset += sprintf (line+offset, "  ");
471         offset += sprintf (line+offset, " - ");
472
473         for (i = 0; i <= from; i++) {
474                 if (buffer[base+i] >= 32 && buffer[base+i] <= 126)
475                         line[offset++] = buffer[base+i];
476                 else
477                         line[offset++] = '.';
478         }
479         line[offset] = 0;
480         US_DEBUGP("%s\n", line);
481         offset = 0;
482 }
483 #endif
484