| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | /* Driver for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  * | 
					
						
							|  |  |  |  * $Id: shuttle_usbat.c,v 1.17 2002/04/22 03:39:43 mdharm Exp $ | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Current development and maintenance by: | 
					
						
							|  |  |  |  *   (c) 2000, 2001 Robert Baruch (autophile@starband.net) | 
					
						
							|  |  |  |  *   (c) 2004, 2005 Daniel Drake <dsd@gentoo.org> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Developed with the assistance of: | 
					
						
							|  |  |  |  *   (c) 2002 Alan Stern <stern@rowland.org> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Flash support based on earlier work by: | 
					
						
							|  |  |  |  *   (c) 2002 Thomas Kreiling <usbdev@sm04.de> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Many originally ATAPI devices were slightly modified to meet the USB | 
					
						
							|  |  |  |  * market by using some kind of translation from ATAPI to USB on the host, | 
					
						
							|  |  |  |  * and the peripheral would translate from USB back to ATAPI. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * SCM Microsystems (www.scmmicro.com) makes a device, sold to OEM's only,  | 
					
						
							|  |  |  |  * which does the USB-to-ATAPI conversion.  By obtaining the data sheet on | 
					
						
							|  |  |  |  * their device under nondisclosure agreement, I have been able to write | 
					
						
							|  |  |  |  * this driver for Linux. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The chip used in the device can also be used for EPP and ISA translation | 
					
						
							|  |  |  |  * as well. This driver is only guaranteed to work with the ATAPI | 
					
						
							|  |  |  |  * translation. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * See the Kconfig help text for a list of devices known to be supported by | 
					
						
							|  |  |  |  * this driver. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or modify it | 
					
						
							|  |  |  |  * under the terms of the GNU General Public License as published by the | 
					
						
							|  |  |  |  * Free Software Foundation; either version 2, or (at your option) any | 
					
						
							|  |  |  |  * later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, but | 
					
						
							|  |  |  |  * WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
					
						
							|  |  |  |  * General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU General Public License along | 
					
						
							|  |  |  |  * with this program; if not, write to the Free Software Foundation, Inc., | 
					
						
							|  |  |  |  * 675 Mass Ave, Cambridge, MA 02139, USA. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/sched.h>
 | 
					
						
							|  |  |  | #include <linux/errno.h>
 | 
					
						
							|  |  |  | #include <linux/slab.h>
 | 
					
						
							|  |  |  | #include <linux/cdrom.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <scsi/scsi.h>
 | 
					
						
							|  |  |  | #include <scsi/scsi_cmnd.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "usb.h"
 | 
					
						
							|  |  |  | #include "transport.h"
 | 
					
						
							|  |  |  | #include "protocol.h"
 | 
					
						
							|  |  |  | #include "debug.h"
 | 
					
						
							|  |  |  | #include "shuttle_usbat.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define short_pack(LSB,MSB) ( ((u16)(LSB)) | ( ((u16)(MSB))<<8 ) )
 | 
					
						
							|  |  |  | #define LSB_of(s) ((s)&0xFF)
 | 
					
						
							|  |  |  | #define MSB_of(s) ((s)>>8)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int transferred = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us); | 
					
						
							|  |  |  | static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  |  * Convenience function to produce an ATA read/write sectors command | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  * Use cmd=0x20 for read, cmd=0x30 for write | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | static void usbat_pack_ata_sector_cmd(unsigned char *buf, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 					unsigned char thistime, | 
					
						
							|  |  |  | 					u32 sector, unsigned char cmd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	buf[0] = 0; | 
					
						
							|  |  |  | 	buf[1] = thistime; | 
					
						
							|  |  |  | 	buf[2] = sector & 0xFF; | 
					
						
							|  |  |  | 	buf[3] = (sector >>  8) & 0xFF; | 
					
						
							|  |  |  | 	buf[4] = (sector >> 16) & 0xFF; | 
					
						
							|  |  |  | 	buf[5] = 0xE0 | ((sector >> 24) & 0x0F); | 
					
						
							|  |  |  | 	buf[6] = cmd; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Convenience function to get the device type (flash or hp8200) | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_get_device_type(struct us_data *us) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return ((struct usbat_info*)us->extra)->devicetype; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Read a register from the device | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_read(struct us_data *us, | 
					
						
							|  |  |  | 		      unsigned char access, | 
					
						
							|  |  |  | 		      unsigned char reg, | 
					
						
							|  |  |  | 		      unsigned char *content) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return usb_stor_ctrl_transfer(us, | 
					
						
							|  |  |  | 		us->recv_ctrl_pipe, | 
					
						
							|  |  |  | 		access | USBAT_CMD_READ_REG, | 
					
						
							|  |  |  | 		0xC0, | 
					
						
							|  |  |  | 		(u16)reg, | 
					
						
							|  |  |  | 		0, | 
					
						
							|  |  |  | 		content, | 
					
						
							|  |  |  | 		1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Write to a register on the device | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_write(struct us_data *us, | 
					
						
							|  |  |  | 		       unsigned char access, | 
					
						
							|  |  |  | 		       unsigned char reg, | 
					
						
							|  |  |  | 		       unsigned char content) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return usb_stor_ctrl_transfer(us, | 
					
						
							|  |  |  | 		us->send_ctrl_pipe, | 
					
						
							|  |  |  | 		access | USBAT_CMD_WRITE_REG, | 
					
						
							|  |  |  | 		0x40, | 
					
						
							|  |  |  | 		short_pack(reg, content), | 
					
						
							|  |  |  | 		0, | 
					
						
							|  |  |  | 		NULL, | 
					
						
							|  |  |  | 		0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Convenience function to perform a bulk read | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_bulk_read(struct us_data *us, | 
					
						
							|  |  |  | 							 unsigned char *data, | 
					
						
							|  |  |  | 							 unsigned int len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (len == 0) | 
					
						
							|  |  |  | 		return USB_STOR_XFER_GOOD; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	US_DEBUGP("usbat_bulk_read: len = %d\n", len); | 
					
						
							|  |  |  | 	return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, data, len, NULL); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Convenience function to perform a bulk write | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_bulk_write(struct us_data *us, | 
					
						
							|  |  |  | 							unsigned char *data, | 
					
						
							|  |  |  | 							unsigned int len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (len == 0) | 
					
						
							|  |  |  | 		return USB_STOR_XFER_GOOD; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	US_DEBUGP("usbat_bulk_write:  len = %d\n", len); | 
					
						
							|  |  |  | 	return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, data, len, NULL); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Some USBAT-specific commands can only be executed over a command transport | 
					
						
							|  |  |  |  * This transport allows one (len=8) or two (len=16) vendor-specific commands | 
					
						
							|  |  |  |  * to be executed. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_execute_command(struct us_data *us, | 
					
						
							|  |  |  | 								 unsigned char *commands, | 
					
						
							|  |  |  | 								 unsigned int len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, | 
					
						
							|  |  |  | 								  USBAT_CMD_EXEC_CMD, 0x40, 0, 0, | 
					
						
							|  |  |  | 								  commands, len); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Read the status register | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_get_status(struct us_data *us, unsigned char *status) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int rc; | 
					
						
							|  |  |  | 	rc = usbat_read(us, USBAT_ATA, USBAT_ATA_STATUS, status); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	US_DEBUGP("usbat_get_status: 0x%02X\n", (unsigned short) (*status)); | 
					
						
							|  |  |  | 	return rc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Check the device status | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_check_status(struct us_data *us) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned char *reply = us->iobuf; | 
					
						
							|  |  |  | 	int rc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!us) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rc = usbat_get_status(us, reply); | 
					
						
							|  |  |  | 	if (rc != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_FAILED; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/* error/check condition (0x51 is ok) */ | 
					
						
							|  |  |  | 	if (*reply & 0x01 && *reply != 0x51) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		return USB_STOR_TRANSPORT_FAILED; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/* device fault */ | 
					
						
							|  |  |  | 	if (*reply & 0x20) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		return USB_STOR_TRANSPORT_FAILED; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return USB_STOR_TRANSPORT_GOOD; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Stores critical information in internal registers in prepartion for the execution | 
					
						
							|  |  |  |  * of a conditional usbat_read_blocks or usbat_write_blocks call. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_set_shuttle_features(struct us_data *us, | 
					
						
							|  |  |  | 				      unsigned char external_trigger, | 
					
						
							|  |  |  | 				      unsigned char epp_control, | 
					
						
							|  |  |  | 				      unsigned char mask_byte, | 
					
						
							|  |  |  | 				      unsigned char test_pattern, | 
					
						
							|  |  |  | 				      unsigned char subcountH, | 
					
						
							|  |  |  | 				      unsigned char subcountL) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned char *command = us->iobuf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	command[0] = 0x40; | 
					
						
							|  |  |  | 	command[1] = USBAT_CMD_SET_FEAT; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * The only bit relevant to ATA access is bit 6 | 
					
						
							|  |  |  | 	 * which defines 8 bit data access (set) or 16 bit (unset) | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	command[2] = epp_control; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * If FCQ is set in the qualifier (defined in R/W cmd), then bits U0, U1, | 
					
						
							|  |  |  | 	 * ET1 and ET2 define an external event to be checked for on event of a | 
					
						
							|  |  |  | 	 * _read_blocks or _write_blocks operation. The read/write will not take | 
					
						
							|  |  |  | 	 * place unless the defined trigger signal is active. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	command[3] = external_trigger; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * The resultant byte of the mask operation (see mask_byte) is compared for | 
					
						
							|  |  |  | 	 * equivalence with this test pattern. If equal, the read/write will take | 
					
						
							|  |  |  | 	 * place. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	command[4] = test_pattern; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * This value is logically ANDed with the status register field specified | 
					
						
							|  |  |  | 	 * in the read/write command. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	command[5] = mask_byte; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * If ALQ is set in the qualifier, this field contains the address of the | 
					
						
							|  |  |  | 	 * registers where the byte count should be read for transferring the data. | 
					
						
							|  |  |  | 	 * If ALQ is not set, then this field contains the number of bytes to be | 
					
						
							|  |  |  | 	 * transferred. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	command[6] = subcountL; | 
					
						
							|  |  |  | 	command[7] = subcountH; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return usbat_execute_command(us, command, 8); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Block, waiting for an ATA device to become not busy or to report | 
					
						
							|  |  |  |  * an error condition. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_wait_not_busy(struct us_data *us, int minutes) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 	int result; | 
					
						
							|  |  |  | 	unsigned char *status = us->iobuf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Synchronizing cache on a CDR could take a heck of a long time,
 | 
					
						
							|  |  |  | 	 * but probably not more than 10 minutes or so. On the other hand, | 
					
						
							|  |  |  | 	 * doing a full blank on a CDRW at speed 1 will take about 75 | 
					
						
							|  |  |  | 	 * minutes! | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i=0; i<1200+minutes*60; i++) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  		result = usbat_get_status(us, status); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (result!=USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 			return USB_STOR_TRANSPORT_ERROR; | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		if (*status & 0x01) { /* check condition */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			result = usbat_read(us, USBAT_ATA, 0x10, status); | 
					
						
							|  |  |  | 			return USB_STOR_TRANSPORT_FAILED; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		if (*status & 0x20) /* device fault */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			return USB_STOR_TRANSPORT_FAILED; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		if ((*status & 0x80)==0x00) { /* not busy */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			US_DEBUGP("Waited not busy for %d steps\n", i); | 
					
						
							|  |  |  | 			return USB_STOR_TRANSPORT_GOOD; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (i<500) | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 			msleep(10); /* 5 seconds */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		else if (i<700) | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 			msleep(50); /* 10 seconds */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		else if (i<1200) | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 			msleep(100); /* 50 seconds */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		else | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 			msleep(1000); /* X minutes */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	US_DEBUGP("Waited not busy for %d minutes, timing out.\n", | 
					
						
							|  |  |  | 		minutes); | 
					
						
							|  |  |  | 	return USB_STOR_TRANSPORT_FAILED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Read block data from the data register | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_read_block(struct us_data *us, | 
					
						
							|  |  |  | 			    unsigned char *content, | 
					
						
							|  |  |  | 			    unsigned short len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int result; | 
					
						
							|  |  |  | 	unsigned char *command = us->iobuf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!len) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_GOOD; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	command[0] = 0xC0; | 
					
						
							|  |  |  | 	command[1] = USBAT_ATA | USBAT_CMD_READ_BLOCK; | 
					
						
							|  |  |  | 	command[2] = USBAT_ATA_DATA; | 
					
						
							|  |  |  | 	command[3] = 0; | 
					
						
							|  |  |  | 	command[4] = 0; | 
					
						
							|  |  |  | 	command[5] = 0; | 
					
						
							|  |  |  | 	command[6] = LSB_of(len); | 
					
						
							|  |  |  | 	command[7] = MSB_of(len); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	result = usbat_execute_command(us, command, 8); | 
					
						
							|  |  |  | 	if (result != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	result = usbat_bulk_read(us, content, len); | 
					
						
							|  |  |  | 	return (result == USB_STOR_XFER_GOOD ? | 
					
						
							|  |  |  | 			USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Write block data via the data register | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_write_block(struct us_data *us, | 
					
						
							|  |  |  | 			     unsigned char access, | 
					
						
							|  |  |  | 			     unsigned char *content, | 
					
						
							|  |  |  | 			     unsigned short len, | 
					
						
							|  |  |  | 			     int minutes) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int result; | 
					
						
							|  |  |  | 	unsigned char *command = us->iobuf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!len) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_GOOD; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	command[0] = 0x40; | 
					
						
							|  |  |  | 	command[1] = access | USBAT_CMD_WRITE_BLOCK; | 
					
						
							|  |  |  | 	command[2] = USBAT_ATA_DATA; | 
					
						
							|  |  |  | 	command[3] = 0; | 
					
						
							|  |  |  | 	command[4] = 0; | 
					
						
							|  |  |  | 	command[5] = 0; | 
					
						
							|  |  |  | 	command[6] = LSB_of(len); | 
					
						
							|  |  |  | 	command[7] = MSB_of(len); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	result = usbat_execute_command(us, command, 8); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (result != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	result = usbat_bulk_write(us, content, len); | 
					
						
							|  |  |  | 	if (result != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return usbat_wait_not_busy(us, minutes); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Process read and write requests | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_hp8200e_rw_block_test(struct us_data *us, | 
					
						
							|  |  |  | 				       unsigned char access, | 
					
						
							|  |  |  | 				       unsigned char *registers, | 
					
						
							|  |  |  | 				       unsigned char *data_out, | 
					
						
							|  |  |  | 				       unsigned short num_registers, | 
					
						
							|  |  |  | 				       unsigned char data_reg, | 
					
						
							|  |  |  | 				       unsigned char status_reg, | 
					
						
							|  |  |  | 				       unsigned char timeout, | 
					
						
							|  |  |  | 				       unsigned char qualifier, | 
					
						
							|  |  |  | 				       int direction, | 
					
						
							|  |  |  | 				       unsigned char *content, | 
					
						
							|  |  |  | 				       unsigned short len, | 
					
						
							|  |  |  | 				       int use_sg, | 
					
						
							|  |  |  | 				       int minutes) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int result; | 
					
						
							|  |  |  | 	unsigned int pipe = (direction == DMA_FROM_DEVICE) ? | 
					
						
							|  |  |  | 			us->recv_bulk_pipe : us->send_bulk_pipe; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	unsigned char *command = us->iobuf; | 
					
						
							|  |  |  | 	int i, j; | 
					
						
							|  |  |  | 	int cmdlen; | 
					
						
							|  |  |  | 	unsigned char *data = us->iobuf; | 
					
						
							|  |  |  | 	unsigned char *status = us->iobuf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	BUG_ON(num_registers > US_IOBUF_SIZE/2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i=0; i<20; i++) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * The first time we send the full command, which consists | 
					
						
							|  |  |  | 		 * of downloading the SCSI command followed by downloading | 
					
						
							|  |  |  | 		 * the data via a write-and-test.  Any other time we only | 
					
						
							|  |  |  | 		 * send the command to download the data -- the SCSI command | 
					
						
							|  |  |  | 		 * is still 'active' in some sense in the device. | 
					
						
							|  |  |  | 		 *  | 
					
						
							|  |  |  | 		 * We're only going to try sending the data 10 times. After | 
					
						
							|  |  |  | 		 * that, we just return a failure. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (i==0) { | 
					
						
							|  |  |  | 			cmdlen = 16; | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * Write to multiple registers | 
					
						
							|  |  |  | 			 * Not really sure the 0x07, 0x17, 0xfc, 0xe7 is | 
					
						
							|  |  |  | 			 * necessary here, but that's what came out of the | 
					
						
							|  |  |  | 			 * trace every single time. | 
					
						
							|  |  |  | 			 */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			command[0] = 0x40; | 
					
						
							|  |  |  | 			command[1] = access | USBAT_CMD_WRITE_REGS; | 
					
						
							|  |  |  | 			command[2] = 0x07; | 
					
						
							|  |  |  | 			command[3] = 0x17; | 
					
						
							|  |  |  | 			command[4] = 0xFC; | 
					
						
							|  |  |  | 			command[5] = 0xE7; | 
					
						
							|  |  |  | 			command[6] = LSB_of(num_registers*2); | 
					
						
							|  |  |  | 			command[7] = MSB_of(num_registers*2); | 
					
						
							|  |  |  | 		} else | 
					
						
							|  |  |  | 			cmdlen = 8; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		/* Conditionally read or write blocks */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		command[cmdlen-8] = (direction==DMA_TO_DEVICE ? 0x40 : 0xC0); | 
					
						
							|  |  |  | 		command[cmdlen-7] = access | | 
					
						
							|  |  |  | 				(direction==DMA_TO_DEVICE ? | 
					
						
							|  |  |  | 				 USBAT_CMD_COND_WRITE_BLOCK : USBAT_CMD_COND_READ_BLOCK); | 
					
						
							|  |  |  | 		command[cmdlen-6] = data_reg; | 
					
						
							|  |  |  | 		command[cmdlen-5] = status_reg; | 
					
						
							|  |  |  | 		command[cmdlen-4] = timeout; | 
					
						
							|  |  |  | 		command[cmdlen-3] = qualifier; | 
					
						
							|  |  |  | 		command[cmdlen-2] = LSB_of(len); | 
					
						
							|  |  |  | 		command[cmdlen-1] = MSB_of(len); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		result = usbat_execute_command(us, command, cmdlen); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (result != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 			return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (i==0) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			for (j=0; j<num_registers; j++) { | 
					
						
							|  |  |  | 				data[j<<1] = registers[j]; | 
					
						
							|  |  |  | 				data[1+(j<<1)] = data_out[j]; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			result = usbat_bulk_write(us, data, num_registers*2); | 
					
						
							|  |  |  | 			if (result != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 				return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		result = usb_stor_bulk_transfer_sg(us, | 
					
						
							|  |  |  | 			pipe, content, len, use_sg, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * If we get a stall on the bulk download, we'll retry | 
					
						
							|  |  |  | 		 * the bulk download -- but not the SCSI command because | 
					
						
							|  |  |  | 		 * in some sense the SCSI command is still 'active' and | 
					
						
							|  |  |  | 		 * waiting for the data. Don't ask me why this should be; | 
					
						
							|  |  |  | 		 * I'm only following what the Windoze driver did. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * Note that a stall for the test-and-read/write command means | 
					
						
							|  |  |  | 		 * that the test failed. In this case we're testing to make | 
					
						
							|  |  |  | 		 * sure that the device is error-free | 
					
						
							|  |  |  | 		 * (i.e. bit 0 -- CHK -- of status is 0). The most likely | 
					
						
							|  |  |  | 		 * hypothesis is that the USBAT chip somehow knows what | 
					
						
							|  |  |  | 		 * the device will accept, but doesn't give the device any | 
					
						
							|  |  |  | 		 * data until all data is received. Thus, the device would | 
					
						
							|  |  |  | 		 * still be waiting for the first byte of data if a stall | 
					
						
							|  |  |  | 		 * occurs, even if the stall implies that some data was | 
					
						
							|  |  |  | 		 * transferred. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (result == USB_STOR_XFER_SHORT || | 
					
						
							|  |  |  | 				result == USB_STOR_XFER_STALLED) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * If we're reading and we stalled, then clear | 
					
						
							|  |  |  | 			 * the bulk output pipe only the first time. | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (direction==DMA_FROM_DEVICE && i==0) { | 
					
						
							|  |  |  | 				if (usb_stor_clear_halt(us, | 
					
						
							|  |  |  | 						us->send_bulk_pipe) < 0) | 
					
						
							|  |  |  | 					return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * Read status: is the device angry, or just busy? | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  			result = usbat_read(us, USBAT_ATA,  | 
					
						
							|  |  |  | 				direction==DMA_TO_DEVICE ? | 
					
						
							|  |  |  | 					USBAT_ATA_STATUS : USBAT_ATA_ALTSTATUS, | 
					
						
							|  |  |  | 				status); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (result!=USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 				return USB_STOR_TRANSPORT_ERROR; | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 			if (*status & 0x01) /* check condition */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 				return USB_STOR_TRANSPORT_FAILED; | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 			if (*status & 0x20) /* device fault */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 				return USB_STOR_TRANSPORT_FAILED; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			US_DEBUGP("Redoing %s\n", | 
					
						
							|  |  |  | 			  direction==DMA_TO_DEVICE ? "write" : "read"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		} else if (result != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 			return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			return usbat_wait_not_busy(us, minutes); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	US_DEBUGP("Bummer! %s bulk data 20 times failed.\n", | 
					
						
							|  |  |  | 		direction==DMA_TO_DEVICE ? "Writing" : "Reading"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return USB_STOR_TRANSPORT_FAILED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Write to multiple registers: | 
					
						
							|  |  |  |  * Allows us to write specific data to any registers. The data to be written | 
					
						
							|  |  |  |  * gets packed in this sequence: reg0, data0, reg1, data1, ..., regN, dataN | 
					
						
							|  |  |  |  * which gets sent through bulk out. | 
					
						
							|  |  |  |  * Not designed for large transfers of data! | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_multiple_write(struct us_data *us, | 
					
						
							|  |  |  | 				unsigned char *registers, | 
					
						
							|  |  |  | 				unsigned char *data_out, | 
					
						
							|  |  |  | 				unsigned short num_registers) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i, result; | 
					
						
							|  |  |  | 	unsigned char *data = us->iobuf; | 
					
						
							|  |  |  | 	unsigned char *command = us->iobuf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	BUG_ON(num_registers > US_IOBUF_SIZE/2); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/* Write to multiple registers, ATA access */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	command[0] = 0x40; | 
					
						
							|  |  |  | 	command[1] = USBAT_ATA | USBAT_CMD_WRITE_REGS; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/* No relevance */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	command[2] = 0; | 
					
						
							|  |  |  | 	command[3] = 0; | 
					
						
							|  |  |  | 	command[4] = 0; | 
					
						
							|  |  |  | 	command[5] = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/* Number of bytes to be transferred (incl. addresses and data) */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	command[6] = LSB_of(num_registers*2); | 
					
						
							|  |  |  | 	command[7] = MSB_of(num_registers*2); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/* The setup command */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	result = usbat_execute_command(us, command, 8); | 
					
						
							|  |  |  | 	if (result != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/* Create the reg/data, reg/data sequence */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	for (i=0; i<num_registers; i++) { | 
					
						
							|  |  |  | 		data[i<<1] = registers[i]; | 
					
						
							|  |  |  | 		data[1+(i<<1)] = data_out[i]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/* Send the data */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	result = usbat_bulk_write(us, data, num_registers*2); | 
					
						
							|  |  |  | 	if (result != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (usbat_get_device_type(us) == USBAT_DEV_HP8200) | 
					
						
							|  |  |  | 		return usbat_wait_not_busy(us, 0); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_GOOD; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Conditionally read blocks from device: | 
					
						
							|  |  |  |  * Allows us to read blocks from a specific data register, based upon the | 
					
						
							|  |  |  |  * condition that a status register can be successfully masked with a status | 
					
						
							|  |  |  |  * qualifier. If this condition is not initially met, the read will wait | 
					
						
							|  |  |  |  * up until a maximum amount of time has elapsed, as specified by timeout. | 
					
						
							|  |  |  |  * The read will start when the condition is met, otherwise the command aborts. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The qualifier defined here is not the value that is masked, it defines | 
					
						
							|  |  |  |  * conditions for the write to take place. The actual masked qualifier (and | 
					
						
							|  |  |  |  * other related details) are defined beforehand with _set_shuttle_features(). | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_read_blocks(struct us_data *us, | 
					
						
							|  |  |  | 							 unsigned char *buffer, | 
					
						
							|  |  |  | 							 int len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int result; | 
					
						
							|  |  |  | 	unsigned char *command = us->iobuf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	command[0] = 0xC0; | 
					
						
							|  |  |  | 	command[1] = USBAT_ATA | USBAT_CMD_COND_READ_BLOCK; | 
					
						
							|  |  |  | 	command[2] = USBAT_ATA_DATA; | 
					
						
							|  |  |  | 	command[3] = USBAT_ATA_STATUS; | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	command[4] = 0xFD; /* Timeout (ms); */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	command[5] = USBAT_QUAL_FCQ; | 
					
						
							|  |  |  | 	command[6] = LSB_of(len); | 
					
						
							|  |  |  | 	command[7] = MSB_of(len); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/* Multiple block read setup command */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	result = usbat_execute_command(us, command, 8); | 
					
						
							|  |  |  | 	if (result != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_FAILED; | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/* Read the blocks we just asked for */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	result = usbat_bulk_read(us, buffer, len); | 
					
						
							|  |  |  | 	if (result != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_FAILED; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return USB_STOR_TRANSPORT_GOOD; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Conditionally write blocks to device: | 
					
						
							|  |  |  |  * Allows us to write blocks to a specific data register, based upon the | 
					
						
							|  |  |  |  * condition that a status register can be successfully masked with a status | 
					
						
							|  |  |  |  * qualifier. If this condition is not initially met, the write will wait | 
					
						
							|  |  |  |  * up until a maximum amount of time has elapsed, as specified by timeout. | 
					
						
							|  |  |  |  * The read will start when the condition is met, otherwise the command aborts. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The qualifier defined here is not the value that is masked, it defines | 
					
						
							|  |  |  |  * conditions for the write to take place. The actual masked qualifier (and | 
					
						
							|  |  |  |  * other related details) are defined beforehand with _set_shuttle_features(). | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_write_blocks(struct us_data *us, | 
					
						
							|  |  |  | 							  unsigned char *buffer, | 
					
						
							|  |  |  | 							  int len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int result; | 
					
						
							|  |  |  | 	unsigned char *command = us->iobuf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	command[0] = 0x40; | 
					
						
							|  |  |  | 	command[1] = USBAT_ATA | USBAT_CMD_COND_WRITE_BLOCK; | 
					
						
							|  |  |  | 	command[2] = USBAT_ATA_DATA; | 
					
						
							|  |  |  | 	command[3] = USBAT_ATA_STATUS; | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	command[4] = 0xFD; /* Timeout (ms) */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	command[5] = USBAT_QUAL_FCQ; | 
					
						
							|  |  |  | 	command[6] = LSB_of(len); | 
					
						
							|  |  |  | 	command[7] = MSB_of(len); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/* Multiple block write setup command */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	result = usbat_execute_command(us, command, 8); | 
					
						
							|  |  |  | 	if (result != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_FAILED; | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/* Write the data */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	result = usbat_bulk_write(us, buffer, len); | 
					
						
							|  |  |  | 	if (result != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_FAILED; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return USB_STOR_TRANSPORT_GOOD; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Read the User IO register | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_read_user_io(struct us_data *us, unsigned char *data_flags) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int result; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	result = usb_stor_ctrl_transfer(us, | 
					
						
							|  |  |  | 		us->recv_ctrl_pipe, | 
					
						
							|  |  |  | 		USBAT_CMD_UIO, | 
					
						
							|  |  |  | 		0xC0, | 
					
						
							|  |  |  | 		0, | 
					
						
							|  |  |  | 		0, | 
					
						
							|  |  |  | 		data_flags, | 
					
						
							|  |  |  | 		USBAT_UIO_READ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	US_DEBUGP("usbat_read_user_io: UIO register reads %02X\n", (unsigned short) (*data_flags)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Write to the User IO register | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_write_user_io(struct us_data *us, | 
					
						
							|  |  |  | 			       unsigned char enable_flags, | 
					
						
							|  |  |  | 			       unsigned char data_flags) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return usb_stor_ctrl_transfer(us, | 
					
						
							|  |  |  | 		us->send_ctrl_pipe, | 
					
						
							|  |  |  | 		USBAT_CMD_UIO, | 
					
						
							|  |  |  | 		0x40, | 
					
						
							|  |  |  | 		short_pack(enable_flags, data_flags), | 
					
						
							|  |  |  | 		0, | 
					
						
							|  |  |  | 		NULL, | 
					
						
							|  |  |  | 		USBAT_UIO_WRITE); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Reset the device | 
					
						
							|  |  |  |  * Often needed on media change. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_device_reset(struct us_data *us) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int rc; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Reset peripheral, enable peripheral control signals | 
					
						
							|  |  |  | 	 * (bring reset signal up) | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	rc = usbat_write_user_io(us, | 
					
						
							|  |  |  | 							 USBAT_UIO_DRVRST | USBAT_UIO_OE1 | USBAT_UIO_OE0, | 
					
						
							|  |  |  | 							 USBAT_UIO_EPAD | USBAT_UIO_1); | 
					
						
							|  |  |  | 	if (rc != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 			 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Enable peripheral control signals | 
					
						
							|  |  |  | 	 * (bring reset signal down) | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	rc = usbat_write_user_io(us, | 
					
						
							|  |  |  | 							 USBAT_UIO_OE1  | USBAT_UIO_OE0, | 
					
						
							|  |  |  | 							 USBAT_UIO_EPAD | USBAT_UIO_1); | 
					
						
							|  |  |  | 	if (rc != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return USB_STOR_TRANSPORT_GOOD; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Enable card detect | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_device_enable_cdt(struct us_data *us) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int rc; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/* Enable peripheral control signals and card detect */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	rc = usbat_write_user_io(us, | 
					
						
							|  |  |  | 							 USBAT_UIO_ACKD | USBAT_UIO_OE1  | USBAT_UIO_OE0, | 
					
						
							|  |  |  | 							 USBAT_UIO_EPAD | USBAT_UIO_1); | 
					
						
							|  |  |  | 	if (rc != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return USB_STOR_TRANSPORT_GOOD; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Determine if media is present. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_flash_check_media_present(unsigned char *uio) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (*uio & USBAT_UIO_UI0) { | 
					
						
							|  |  |  | 		US_DEBUGP("usbat_flash_check_media_present: no media detected\n"); | 
					
						
							|  |  |  | 		return USBAT_FLASH_MEDIA_NONE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return USBAT_FLASH_MEDIA_CF; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Determine if media has changed since last operation | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_flash_check_media_changed(unsigned char *uio) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (*uio & USBAT_UIO_0) { | 
					
						
							|  |  |  | 		US_DEBUGP("usbat_flash_check_media_changed: media change detected\n"); | 
					
						
							|  |  |  | 		return USBAT_FLASH_MEDIA_CHANGED; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return USBAT_FLASH_MEDIA_SAME; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Check for media change / no media and handle the situation appropriately | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_flash_check_media(struct us_data *us, | 
					
						
							|  |  |  | 				   struct usbat_info *info) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int rc; | 
					
						
							|  |  |  | 	unsigned char *uio = us->iobuf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rc = usbat_read_user_io(us, uio); | 
					
						
							|  |  |  | 	if (rc != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/* Check for media existence */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	rc = usbat_flash_check_media_present(uio); | 
					
						
							|  |  |  | 	if (rc == USBAT_FLASH_MEDIA_NONE) { | 
					
						
							|  |  |  | 		info->sense_key = 0x02; | 
					
						
							|  |  |  | 		info->sense_asc = 0x3A; | 
					
						
							|  |  |  | 		info->sense_ascq = 0x00; | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_FAILED; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/* Check for media change */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	rc = usbat_flash_check_media_changed(uio); | 
					
						
							|  |  |  | 	if (rc == USBAT_FLASH_MEDIA_CHANGED) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		/* Reset and re-enable card detect */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		rc = usbat_device_reset(us); | 
					
						
							|  |  |  | 		if (rc != USB_STOR_TRANSPORT_GOOD) | 
					
						
							|  |  |  | 			return rc; | 
					
						
							|  |  |  | 		rc = usbat_device_enable_cdt(us); | 
					
						
							|  |  |  | 		if (rc != USB_STOR_TRANSPORT_GOOD) | 
					
						
							|  |  |  | 			return rc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		msleep(50); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		rc = usbat_read_user_io(us, uio); | 
					
						
							|  |  |  | 		if (rc != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 			return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		info->sense_key = UNIT_ATTENTION; | 
					
						
							|  |  |  | 		info->sense_asc = 0x28; | 
					
						
							|  |  |  | 		info->sense_ascq = 0x00; | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_FAILED; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return USB_STOR_TRANSPORT_GOOD; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Determine whether we are controlling a flash-based reader/writer, | 
					
						
							|  |  |  |  * or a HP8200-based CD drive. | 
					
						
							|  |  |  |  * Sets transport functions as appropriate. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_identify_device(struct us_data *us, | 
					
						
							|  |  |  | 				 struct usbat_info *info) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int rc; | 
					
						
							|  |  |  | 	unsigned char status; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!us || !info) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rc = usbat_device_reset(us); | 
					
						
							|  |  |  | 	if (rc != USB_STOR_TRANSPORT_GOOD) | 
					
						
							|  |  |  | 		return rc; | 
					
						
							| 
									
										
										
										
											2005-11-17 09:48:01 -08:00
										 |  |  | 	msleep(500); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							| 
									
										
										
										
											2005-08-10 18:30:04 +01:00
										 |  |  | 	 * In attempt to distinguish between HP CDRW's and Flash readers, we now | 
					
						
							|  |  |  | 	 * execute the IDENTIFY PACKET DEVICE command. On ATA devices (i.e. flash | 
					
						
							|  |  |  | 	 * readers), this command should fail with error. On ATAPI devices (i.e. | 
					
						
							|  |  |  | 	 * CDROM drives), it should succeed. | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2005-08-10 18:30:04 +01:00
										 |  |  | 	rc = usbat_write(us, USBAT_ATA, USBAT_ATA_CMD, 0xA1); | 
					
						
							|  |  |  |  	if (rc != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  |  		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-08-10 18:30:04 +01:00
										 |  |  | 	rc = usbat_get_status(us, &status); | 
					
						
							|  |  |  |  	if (rc != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  |  		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/* Check for error bit, or if the command 'fell through' */ | 
					
						
							| 
									
										
										
										
											2005-09-29 00:14:21 +01:00
										 |  |  | 	if (status == 0xA1 || !(status & 0x01)) { | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		/* Device is HP 8200 */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		US_DEBUGP("usbat_identify_device: Detected HP8200 CDRW\n"); | 
					
						
							|  |  |  | 		info->devicetype = USBAT_DEV_HP8200; | 
					
						
							| 
									
										
										
										
											2005-09-29 00:14:21 +01:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		/* Device is a CompactFlash reader/writer */ | 
					
						
							| 
									
										
										
										
											2005-09-29 00:14:21 +01:00
										 |  |  | 		US_DEBUGP("usbat_identify_device: Detected Flash reader/writer\n"); | 
					
						
							|  |  |  | 		info->devicetype = USBAT_DEV_FLASH; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return USB_STOR_TRANSPORT_GOOD; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Set the transport function based on the device type | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_set_transport(struct us_data *us, | 
					
						
							|  |  |  | 			       struct usbat_info *info) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int rc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!info->devicetype) { | 
					
						
							|  |  |  | 		rc = usbat_identify_device(us, info); | 
					
						
							|  |  |  | 		if (rc != USB_STOR_TRANSPORT_GOOD) { | 
					
						
							|  |  |  | 			US_DEBUGP("usbat_set_transport: Could not identify device\n"); | 
					
						
							|  |  |  | 			return 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (usbat_get_device_type(us) == USBAT_DEV_HP8200) | 
					
						
							|  |  |  | 		us->transport = usbat_hp8200e_transport; | 
					
						
							|  |  |  | 	else if (usbat_get_device_type(us) == USBAT_DEV_FLASH) | 
					
						
							|  |  |  | 		us->transport = usbat_flash_transport; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Read the media capacity | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_flash_get_sector_count(struct us_data *us, | 
					
						
							|  |  |  | 					struct usbat_info *info) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned char registers[3] = { | 
					
						
							|  |  |  | 		USBAT_ATA_SECCNT, | 
					
						
							|  |  |  | 		USBAT_ATA_DEVICE, | 
					
						
							|  |  |  | 		USBAT_ATA_CMD, | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 	unsigned char  command[3] = { 0x01, 0xA0, 0xEC }; | 
					
						
							|  |  |  | 	unsigned char *reply; | 
					
						
							|  |  |  | 	unsigned char status; | 
					
						
							|  |  |  | 	int rc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!us || !info) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	reply = kmalloc(512, GFP_NOIO); | 
					
						
							|  |  |  | 	if (!reply) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/* ATA command : IDENTIFY DEVICE */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	rc = usbat_multiple_write(us, registers, command, 3); | 
					
						
							|  |  |  | 	if (rc != USB_STOR_XFER_GOOD) { | 
					
						
							|  |  |  | 		US_DEBUGP("usbat_flash_get_sector_count: Gah! identify_device failed\n"); | 
					
						
							|  |  |  | 		rc = USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 		goto leave; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/* Read device status */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (usbat_get_status(us, &status) != USB_STOR_XFER_GOOD) { | 
					
						
							|  |  |  | 		rc = USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 		goto leave; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	msleep(100); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/* Read the device identification data */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	rc = usbat_read_block(us, reply, 512); | 
					
						
							|  |  |  | 	if (rc != USB_STOR_TRANSPORT_GOOD) | 
					
						
							|  |  |  | 		goto leave; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	info->sectors = ((u32)(reply[117]) << 24) | | 
					
						
							|  |  |  | 		((u32)(reply[116]) << 16) | | 
					
						
							|  |  |  | 		((u32)(reply[115]) <<  8) | | 
					
						
							|  |  |  | 		((u32)(reply[114])      ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rc = USB_STOR_TRANSPORT_GOOD; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  leave: | 
					
						
							|  |  |  | 	kfree(reply); | 
					
						
							|  |  |  | 	return rc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Read data from device | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_flash_read_data(struct us_data *us, | 
					
						
							|  |  |  | 								 struct usbat_info *info, | 
					
						
							|  |  |  | 								 u32 sector, | 
					
						
							|  |  |  | 								 u32 sectors) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned char registers[7] = { | 
					
						
							|  |  |  | 		USBAT_ATA_FEATURES, | 
					
						
							|  |  |  | 		USBAT_ATA_SECCNT, | 
					
						
							|  |  |  | 		USBAT_ATA_SECNUM, | 
					
						
							|  |  |  | 		USBAT_ATA_LBA_ME, | 
					
						
							|  |  |  | 		USBAT_ATA_LBA_HI, | 
					
						
							|  |  |  | 		USBAT_ATA_DEVICE, | 
					
						
							|  |  |  | 		USBAT_ATA_STATUS, | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 	unsigned char command[7]; | 
					
						
							|  |  |  | 	unsigned char *buffer; | 
					
						
							|  |  |  | 	unsigned char  thistime; | 
					
						
							|  |  |  | 	unsigned int totallen, alloclen; | 
					
						
							|  |  |  | 	int len, result; | 
					
						
							|  |  |  | 	unsigned int sg_idx = 0, sg_offset = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	result = usbat_flash_check_media(us, info); | 
					
						
							|  |  |  | 	if (result != USB_STOR_TRANSPORT_GOOD) | 
					
						
							|  |  |  | 		return result; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * we're working in LBA mode.  according to the ATA spec, | 
					
						
							|  |  |  | 	 * we can support up to 28-bit addressing.  I don't know if Jumpshot | 
					
						
							|  |  |  | 	 * supports beyond 24-bit addressing.  It's kind of hard to test | 
					
						
							|  |  |  | 	 * since it requires > 8GB CF card. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (sector > 0x0FFFFFFF) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	totallen = sectors * info->ssize; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Since we don't read more than 64 KB at a time, we have to create | 
					
						
							|  |  |  | 	 * a bounce buffer and move the data a piece at a time between the | 
					
						
							|  |  |  | 	 * bounce buffer and the actual transfer buffer. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	alloclen = min(totallen, 65536u); | 
					
						
							|  |  |  | 	buffer = kmalloc(alloclen, GFP_NOIO); | 
					
						
							|  |  |  | 	if (buffer == NULL) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	do { | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * loop, never allocate or transfer more than 64k at once | 
					
						
							|  |  |  | 		 * (min(128k, 255*info->ssize) is the real limit) | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		len = min(totallen, alloclen); | 
					
						
							|  |  |  | 		thistime = (len / info->ssize) & 0xff; | 
					
						
							|  |  |  |   | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		/* ATA command 0x20 (READ SECTORS) */ | 
					
						
							|  |  |  | 		usbat_pack_ata_sector_cmd(command, thistime, sector, 0x20); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		/* Write/execute ATA read command */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		result = usbat_multiple_write(us, registers, command, 7); | 
					
						
							|  |  |  | 		if (result != USB_STOR_TRANSPORT_GOOD) | 
					
						
							|  |  |  | 			goto leave; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		/* Read the data we just requested */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		result = usbat_read_blocks(us, buffer, len); | 
					
						
							|  |  |  | 		if (result != USB_STOR_TRANSPORT_GOOD) | 
					
						
							|  |  |  | 			goto leave; | 
					
						
							|  |  |  |   	  | 
					
						
							|  |  |  | 		US_DEBUGP("usbat_flash_read_data:  %d bytes\n", len); | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		/* Store the data in the transfer buffer */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		usb_stor_access_xfer_buf(buffer, len, us->srb, | 
					
						
							|  |  |  | 					 &sg_idx, &sg_offset, TO_XFER_BUF); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		sector += thistime; | 
					
						
							|  |  |  | 		totallen -= len; | 
					
						
							|  |  |  | 	} while (totallen > 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	kfree(buffer); | 
					
						
							|  |  |  | 	return USB_STOR_TRANSPORT_GOOD; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | leave: | 
					
						
							|  |  |  | 	kfree(buffer); | 
					
						
							|  |  |  | 	return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Write data to device | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_flash_write_data(struct us_data *us, | 
					
						
							|  |  |  | 								  struct usbat_info *info, | 
					
						
							|  |  |  | 								  u32 sector, | 
					
						
							|  |  |  | 								  u32 sectors) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned char registers[7] = { | 
					
						
							|  |  |  | 		USBAT_ATA_FEATURES, | 
					
						
							|  |  |  | 		USBAT_ATA_SECCNT, | 
					
						
							|  |  |  | 		USBAT_ATA_SECNUM, | 
					
						
							|  |  |  | 		USBAT_ATA_LBA_ME, | 
					
						
							|  |  |  | 		USBAT_ATA_LBA_HI, | 
					
						
							|  |  |  | 		USBAT_ATA_DEVICE, | 
					
						
							|  |  |  | 		USBAT_ATA_STATUS, | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 	unsigned char command[7]; | 
					
						
							|  |  |  | 	unsigned char *buffer; | 
					
						
							|  |  |  | 	unsigned char  thistime; | 
					
						
							|  |  |  | 	unsigned int totallen, alloclen; | 
					
						
							|  |  |  | 	int len, result; | 
					
						
							|  |  |  | 	unsigned int sg_idx = 0, sg_offset = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	result = usbat_flash_check_media(us, info); | 
					
						
							|  |  |  | 	if (result != USB_STOR_TRANSPORT_GOOD) | 
					
						
							|  |  |  | 		return result; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * we're working in LBA mode.  according to the ATA spec, | 
					
						
							|  |  |  | 	 * we can support up to 28-bit addressing.  I don't know if the device | 
					
						
							|  |  |  | 	 * supports beyond 24-bit addressing.  It's kind of hard to test | 
					
						
							|  |  |  | 	 * since it requires > 8GB media. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (sector > 0x0FFFFFFF) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	totallen = sectors * info->ssize; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Since we don't write more than 64 KB at a time, we have to create | 
					
						
							|  |  |  | 	 * a bounce buffer and move the data a piece at a time between the | 
					
						
							|  |  |  | 	 * bounce buffer and the actual transfer buffer. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	alloclen = min(totallen, 65536u); | 
					
						
							|  |  |  | 	buffer = kmalloc(alloclen, GFP_NOIO); | 
					
						
							|  |  |  | 	if (buffer == NULL) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	do { | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * loop, never allocate or transfer more than 64k at once | 
					
						
							|  |  |  | 		 * (min(128k, 255*info->ssize) is the real limit) | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		len = min(totallen, alloclen); | 
					
						
							|  |  |  | 		thistime = (len / info->ssize) & 0xff; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		/* Get the data from the transfer buffer */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		usb_stor_access_xfer_buf(buffer, len, us->srb, | 
					
						
							|  |  |  | 					 &sg_idx, &sg_offset, FROM_XFER_BUF); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		/* ATA command 0x30 (WRITE SECTORS) */ | 
					
						
							|  |  |  | 		usbat_pack_ata_sector_cmd(command, thistime, sector, 0x30); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		/* Write/execute ATA write command */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		result = usbat_multiple_write(us, registers, command, 7); | 
					
						
							|  |  |  | 		if (result != USB_STOR_TRANSPORT_GOOD) | 
					
						
							|  |  |  | 			goto leave; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		/* Write the data */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		result = usbat_write_blocks(us, buffer, len); | 
					
						
							|  |  |  | 		if (result != USB_STOR_TRANSPORT_GOOD) | 
					
						
							|  |  |  | 			goto leave; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		sector += thistime; | 
					
						
							|  |  |  | 		totallen -= len; | 
					
						
							|  |  |  | 	} while (totallen > 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	kfree(buffer); | 
					
						
							|  |  |  | 	return result; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | leave: | 
					
						
							|  |  |  | 	kfree(buffer); | 
					
						
							|  |  |  | 	return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Squeeze a potentially huge (> 65535 byte) read10 command into | 
					
						
							|  |  |  |  * a little ( <= 65535 byte) ATAPI pipe | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_hp8200e_handle_read10(struct us_data *us, | 
					
						
							|  |  |  | 				       unsigned char *registers, | 
					
						
							|  |  |  | 				       unsigned char *data, | 
					
						
							|  |  |  | 				       struct scsi_cmnd *srb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int result = USB_STOR_TRANSPORT_GOOD; | 
					
						
							|  |  |  | 	unsigned char *buffer; | 
					
						
							|  |  |  | 	unsigned int len; | 
					
						
							|  |  |  | 	unsigned int sector; | 
					
						
							|  |  |  | 	unsigned int sg_segment = 0; | 
					
						
							|  |  |  | 	unsigned int sg_offset = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	US_DEBUGP("handle_read10: transfersize %d\n", | 
					
						
							|  |  |  | 		srb->transfersize); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (srb->request_bufflen < 0x10000) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		result = usbat_hp8200e_rw_block_test(us, USBAT_ATA,  | 
					
						
							|  |  |  | 			registers, data, 19, | 
					
						
							|  |  |  | 			USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD, | 
					
						
							|  |  |  | 			(USBAT_QUAL_FCQ | USBAT_QUAL_ALQ), | 
					
						
							|  |  |  | 			DMA_FROM_DEVICE, | 
					
						
							|  |  |  | 			srb->request_buffer,  | 
					
						
							|  |  |  | 			srb->request_bufflen, srb->use_sg, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return result; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Since we're requesting more data than we can handle in | 
					
						
							|  |  |  | 	 * a single read command (max is 64k-1), we will perform | 
					
						
							|  |  |  | 	 * multiple reads, but each read must be in multiples of | 
					
						
							|  |  |  | 	 * a sector.  Luckily the sector size is in srb->transfersize | 
					
						
							|  |  |  | 	 * (see linux/drivers/scsi/sr.c). | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (data[7+0] == GPCMD_READ_CD) { | 
					
						
							|  |  |  | 		len = short_pack(data[7+9], data[7+8]); | 
					
						
							|  |  |  | 		len <<= 16; | 
					
						
							|  |  |  | 		len |= data[7+7]; | 
					
						
							|  |  |  | 		US_DEBUGP("handle_read10: GPCMD_READ_CD: len %d\n", len); | 
					
						
							|  |  |  | 		srb->transfersize = srb->request_bufflen/len; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!srb->transfersize)  { | 
					
						
							|  |  |  | 		srb->transfersize = 2048; /* A guess */ | 
					
						
							|  |  |  | 		US_DEBUGP("handle_read10: transfersize 0, forcing %d\n", | 
					
						
							|  |  |  | 			srb->transfersize); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Since we only read in one block at a time, we have to create | 
					
						
							|  |  |  | 	 * a bounce buffer and move the data a piece at a time between the | 
					
						
							|  |  |  | 	 * bounce buffer and the actual transfer buffer. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	len = (65535/srb->transfersize) * srb->transfersize; | 
					
						
							|  |  |  | 	US_DEBUGP("Max read is %d bytes\n", len); | 
					
						
							|  |  |  | 	len = min(len, srb->request_bufflen); | 
					
						
							|  |  |  | 	buffer = kmalloc(len, GFP_NOIO); | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	if (buffer == NULL) /* bloody hell! */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		return USB_STOR_TRANSPORT_FAILED; | 
					
						
							|  |  |  | 	sector = short_pack(data[7+3], data[7+2]); | 
					
						
							|  |  |  | 	sector <<= 16; | 
					
						
							|  |  |  | 	sector |= short_pack(data[7+5], data[7+4]); | 
					
						
							|  |  |  | 	transferred = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	sg_segment = 0; /* for keeping track of where we are in */ | 
					
						
							|  |  |  | 	sg_offset = 0;  /* the scatter/gather list */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	while (transferred != srb->request_bufflen) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (len > srb->request_bufflen - transferred) | 
					
						
							|  |  |  | 			len = srb->request_bufflen - transferred; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		data[3] = len&0xFF; 	  /* (cylL) = expected length (L) */ | 
					
						
							|  |  |  | 		data[4] = (len>>8)&0xFF;  /* (cylH) = expected length (H) */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		/* Fix up the SCSI command sector and num sectors */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		data[7+2] = MSB_of(sector>>16); /* SCSI command sector */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		data[7+3] = LSB_of(sector>>16); | 
					
						
							|  |  |  | 		data[7+4] = MSB_of(sector&0xFFFF); | 
					
						
							|  |  |  | 		data[7+5] = LSB_of(sector&0xFFFF); | 
					
						
							|  |  |  | 		if (data[7+0] == GPCMD_READ_CD) | 
					
						
							|  |  |  | 			data[7+6] = 0; | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		data[7+7] = MSB_of(len / srb->transfersize); /* SCSI command */ | 
					
						
							|  |  |  | 		data[7+8] = LSB_of(len / srb->transfersize); /* num sectors */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		result = usbat_hp8200e_rw_block_test(us, USBAT_ATA,  | 
					
						
							|  |  |  | 			registers, data, 19, | 
					
						
							|  |  |  | 			USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD,  | 
					
						
							|  |  |  | 			(USBAT_QUAL_FCQ | USBAT_QUAL_ALQ), | 
					
						
							|  |  |  | 			DMA_FROM_DEVICE, | 
					
						
							|  |  |  | 			buffer, | 
					
						
							|  |  |  | 			len, 0, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (result != USB_STOR_TRANSPORT_GOOD) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		/* Store the data in the transfer buffer */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		usb_stor_access_xfer_buf(buffer, len, srb, | 
					
						
							|  |  |  | 				 &sg_segment, &sg_offset, TO_XFER_BUF); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		/* Update the amount transferred and the sector number */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		transferred += len; | 
					
						
							|  |  |  | 		sector += len / srb->transfersize; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	} /* while transferred != srb->request_bufflen */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	kfree(buffer); | 
					
						
							|  |  |  | 	return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int usbat_select_and_test_registers(struct us_data *us) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int selector; | 
					
						
							|  |  |  | 	unsigned char *status = us->iobuf; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/* try device = master, then device = slave. */ | 
					
						
							| 
									
										
										
										
											2005-08-10 18:30:04 +01:00
										 |  |  | 	for (selector = 0xA0; selector <= 0xB0; selector += 0x10) { | 
					
						
							|  |  |  | 		if (usbat_write(us, USBAT_ATA, USBAT_ATA_DEVICE, selector) != | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 				USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 			return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (usbat_read(us, USBAT_ATA, USBAT_ATA_STATUS, status) !=  | 
					
						
							|  |  |  | 				USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 			return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (usbat_read(us, USBAT_ATA, USBAT_ATA_DEVICE, status) !=  | 
					
						
							|  |  |  | 				USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 			return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) !=  | 
					
						
							|  |  |  | 				USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 			return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_HI, status) !=  | 
					
						
							|  |  |  | 				USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 			return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (usbat_write(us, USBAT_ATA, USBAT_ATA_LBA_ME, 0x55) !=  | 
					
						
							|  |  |  | 				USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 			return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (usbat_write(us, USBAT_ATA, USBAT_ATA_LBA_HI, 0xAA) !=  | 
					
						
							|  |  |  | 				USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 			return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) !=  | 
					
						
							|  |  |  | 				USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 			return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) !=  | 
					
						
							|  |  |  | 				USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 			return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return USB_STOR_TRANSPORT_GOOD; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Initialize the USBAT processor and the storage device | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | int init_usbat(struct us_data *us) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int rc; | 
					
						
							|  |  |  | 	struct usbat_info *info; | 
					
						
							|  |  |  | 	unsigned char subcountH = USBAT_ATA_LBA_HI; | 
					
						
							|  |  |  | 	unsigned char subcountL = USBAT_ATA_LBA_ME; | 
					
						
							|  |  |  | 	unsigned char *status = us->iobuf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	us->extra = kmalloc(sizeof(struct usbat_info), GFP_NOIO); | 
					
						
							|  |  |  | 	if (!us->extra) { | 
					
						
							|  |  |  | 		US_DEBUGP("init_usbat: Gah! Can't allocate storage for usbat info struct!\n"); | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	memset(us->extra, 0, sizeof(struct usbat_info)); | 
					
						
							|  |  |  | 	info = (struct usbat_info *) (us->extra); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/* Enable peripheral control signals */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	rc = usbat_write_user_io(us, | 
					
						
							|  |  |  | 				 USBAT_UIO_OE1 | USBAT_UIO_OE0, | 
					
						
							|  |  |  | 				 USBAT_UIO_EPAD | USBAT_UIO_1); | 
					
						
							|  |  |  | 	if (rc != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	US_DEBUGP("INIT 1\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	msleep(2000); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rc = usbat_read_user_io(us, status); | 
					
						
							|  |  |  | 	if (rc != USB_STOR_TRANSPORT_GOOD) | 
					
						
							|  |  |  | 		return rc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	US_DEBUGP("INIT 2\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rc = usbat_read_user_io(us, status); | 
					
						
							|  |  |  | 	if (rc != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rc = usbat_read_user_io(us, status); | 
					
						
							|  |  |  | 	if (rc != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	US_DEBUGP("INIT 3\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rc = usbat_select_and_test_registers(us); | 
					
						
							|  |  |  | 	if (rc != USB_STOR_TRANSPORT_GOOD) | 
					
						
							|  |  |  | 		return rc; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-08-10 18:30:04 +01:00
										 |  |  | 	US_DEBUGP("INIT 4\n"); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	rc = usbat_read_user_io(us, status); | 
					
						
							|  |  |  | 	if (rc != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-08-10 18:30:04 +01:00
										 |  |  | 	US_DEBUGP("INIT 5\n"); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/* Enable peripheral control signals and card detect */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	rc = usbat_device_enable_cdt(us); | 
					
						
							|  |  |  | 	if (rc != USB_STOR_TRANSPORT_GOOD) | 
					
						
							|  |  |  | 		return rc; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-08-10 18:30:04 +01:00
										 |  |  | 	US_DEBUGP("INIT 6\n"); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	rc = usbat_read_user_io(us, status); | 
					
						
							|  |  |  | 	if (rc != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-08-10 18:30:04 +01:00
										 |  |  | 	US_DEBUGP("INIT 7\n"); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	msleep(1400); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rc = usbat_read_user_io(us, status); | 
					
						
							|  |  |  | 	if (rc != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-08-10 18:30:04 +01:00
										 |  |  | 	US_DEBUGP("INIT 8\n"); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	rc = usbat_select_and_test_registers(us); | 
					
						
							|  |  |  | 	if (rc != USB_STOR_TRANSPORT_GOOD) | 
					
						
							|  |  |  | 		return rc; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-08-10 18:30:04 +01:00
										 |  |  | 	US_DEBUGP("INIT 9\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/* At this point, we need to detect which device we are using */ | 
					
						
							| 
									
										
										
										
											2005-08-10 18:30:04 +01:00
										 |  |  | 	if (usbat_set_transport(us, info)) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	US_DEBUGP("INIT 10\n"); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (usbat_get_device_type(us) == USBAT_DEV_FLASH) {  | 
					
						
							|  |  |  | 		subcountH = 0x02; | 
					
						
							|  |  |  | 		subcountL = 0x00; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	rc = usbat_set_shuttle_features(us, (USBAT_FEAT_ETEN | USBAT_FEAT_ET2 | USBAT_FEAT_ET1), | 
					
						
							|  |  |  | 									0x00, 0x88, 0x08, subcountH, subcountL); | 
					
						
							|  |  |  | 	if (rc != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-08-10 18:30:04 +01:00
										 |  |  | 	US_DEBUGP("INIT 11\n"); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return USB_STOR_TRANSPORT_GOOD; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Transport for the HP 8200e | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int result; | 
					
						
							|  |  |  | 	unsigned char *status = us->iobuf; | 
					
						
							|  |  |  | 	unsigned char registers[32]; | 
					
						
							|  |  |  | 	unsigned char data[32]; | 
					
						
							|  |  |  | 	unsigned int len; | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 	char string[64]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	len = srb->request_bufflen; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Send A0 (ATA PACKET COMMAND).
 | 
					
						
							|  |  |  | 	   Note: I guess we're never going to get any of the ATA | 
					
						
							|  |  |  | 	   commands... just ATA Packet Commands. | 
					
						
							|  |  |  |  	 */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	registers[0] = USBAT_ATA_FEATURES; | 
					
						
							|  |  |  | 	registers[1] = USBAT_ATA_SECCNT; | 
					
						
							|  |  |  | 	registers[2] = USBAT_ATA_SECNUM; | 
					
						
							|  |  |  | 	registers[3] = USBAT_ATA_LBA_ME; | 
					
						
							|  |  |  | 	registers[4] = USBAT_ATA_LBA_HI; | 
					
						
							|  |  |  | 	registers[5] = USBAT_ATA_DEVICE; | 
					
						
							|  |  |  | 	registers[6] = USBAT_ATA_CMD; | 
					
						
							|  |  |  | 	data[0] = 0x00; | 
					
						
							|  |  |  | 	data[1] = 0x00; | 
					
						
							|  |  |  | 	data[2] = 0x00; | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	data[3] = len&0xFF; 		/* (cylL) = expected length (L) */ | 
					
						
							|  |  |  | 	data[4] = (len>>8)&0xFF; 	/* (cylH) = expected length (H) */ | 
					
						
							|  |  |  | 	data[5] = 0xB0; 		/* (device sel) = slave */ | 
					
						
							|  |  |  | 	data[6] = 0xA0; 		/* (command) = ATA PACKET COMMAND */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for (i=7; i<19; i++) { | 
					
						
							|  |  |  | 		registers[i] = 0x10; | 
					
						
							|  |  |  | 		data[i] = (i-7 >= srb->cmd_len) ? 0 : srb->cmnd[i-7]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	result = usbat_get_status(us, status); | 
					
						
							|  |  |  | 	US_DEBUGP("Status = %02X\n", *status); | 
					
						
							|  |  |  | 	if (result != USB_STOR_XFER_GOOD) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 	if (srb->cmnd[0] == TEST_UNIT_READY) | 
					
						
							|  |  |  | 		transferred = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (srb->sc_data_direction == DMA_TO_DEVICE) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		result = usbat_hp8200e_rw_block_test(us, USBAT_ATA,  | 
					
						
							|  |  |  | 			registers, data, 19, | 
					
						
							|  |  |  | 			USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD, | 
					
						
							|  |  |  | 			(USBAT_QUAL_FCQ | USBAT_QUAL_ALQ), | 
					
						
							|  |  |  | 			DMA_TO_DEVICE, | 
					
						
							|  |  |  | 			srb->request_buffer,  | 
					
						
							|  |  |  | 			len, srb->use_sg, 10); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (result == USB_STOR_TRANSPORT_GOOD) { | 
					
						
							|  |  |  | 			transferred += len; | 
					
						
							|  |  |  | 			US_DEBUGP("Wrote %08X bytes\n", transferred); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return result; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} else if (srb->cmnd[0] == READ_10 || | 
					
						
							|  |  |  | 		   srb->cmnd[0] == GPCMD_READ_CD) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return usbat_hp8200e_handle_read10(us, registers, data, srb); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (len > 0xFFFF) { | 
					
						
							|  |  |  | 		US_DEBUGP("Error: len = %08X... what do I do now?\n", | 
					
						
							|  |  |  | 			len); | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ( (result = usbat_multiple_write(us,  | 
					
						
							|  |  |  | 			registers, data, 7)) != USB_STOR_TRANSPORT_GOOD) { | 
					
						
							|  |  |  | 		return result; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Write the 12-byte command header. | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * If the command is BLANK then set the timer for 75 minutes. | 
					
						
							|  |  |  | 	 * Otherwise set it for 10 minutes. | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * NOTE: THE 8200 DOCUMENTATION STATES THAT BLANKING A CDRW | 
					
						
							|  |  |  | 	 * AT SPEED 4 IS UNRELIABLE!!! | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if ( (result = usbat_write_block(us,  | 
					
						
							|  |  |  | 			USBAT_ATA, srb->cmnd, 12, | 
					
						
							|  |  |  | 			srb->cmnd[0]==GPCMD_BLANK ? 75 : 10)) != | 
					
						
							|  |  |  | 				USB_STOR_TRANSPORT_GOOD) { | 
					
						
							|  |  |  | 		return result; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 	/* If there is response data to be read in then do it here. */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (len != 0 && (srb->sc_data_direction == DMA_FROM_DEVICE)) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		/* How many bytes to read in? Check cylL register */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) !=  | 
					
						
							|  |  |  | 		    	USB_STOR_XFER_GOOD) { | 
					
						
							|  |  |  | 			return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		if (len > 0xFF) { /* need to read cylH also */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			len = *status; | 
					
						
							|  |  |  | 			if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_HI, status) != | 
					
						
							|  |  |  | 				    USB_STOR_XFER_GOOD) { | 
					
						
							|  |  |  | 				return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			len += ((unsigned int) *status)<<8; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			len = *status; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		result = usbat_read_block(us, srb->request_buffer, len); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Debug-print the first 32 bytes of the transfer */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!srb->use_sg) { | 
					
						
							|  |  |  | 			string[0] = 0; | 
					
						
							|  |  |  | 			for (i=0; i<len && i<32; i++) { | 
					
						
							|  |  |  | 				sprintf(string+strlen(string), "%02X ", | 
					
						
							|  |  |  | 				  ((unsigned char *)srb->request_buffer)[i]); | 
					
						
							|  |  |  | 				if ((i%16)==15) { | 
					
						
							|  |  |  | 					US_DEBUGP("%s\n", string); | 
					
						
							|  |  |  | 					string[0] = 0; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (string[0]!=0) | 
					
						
							|  |  |  | 				US_DEBUGP("%s\n", string); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Transport for USBAT02-based CompactFlash and similar storage devices | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int rc; | 
					
						
							|  |  |  | 	struct usbat_info *info = (struct usbat_info *) (us->extra); | 
					
						
							|  |  |  | 	unsigned long block, blocks; | 
					
						
							|  |  |  | 	unsigned char *ptr = us->iobuf; | 
					
						
							|  |  |  | 	static unsigned char inquiry_response[36] = { | 
					
						
							|  |  |  | 		0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00 | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (srb->cmnd[0] == INQUIRY) { | 
					
						
							|  |  |  | 		US_DEBUGP("usbat_flash_transport: INQUIRY. Returning bogus response.\n"); | 
					
						
							|  |  |  | 		memcpy(ptr, inquiry_response, sizeof(inquiry_response)); | 
					
						
							|  |  |  | 		fill_inquiry_response(us, ptr, 36); | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_GOOD; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (srb->cmnd[0] == READ_CAPACITY) { | 
					
						
							|  |  |  | 		rc = usbat_flash_check_media(us, info); | 
					
						
							|  |  |  | 		if (rc != USB_STOR_TRANSPORT_GOOD) | 
					
						
							|  |  |  | 			return rc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		rc = usbat_flash_get_sector_count(us, info); | 
					
						
							|  |  |  | 		if (rc != USB_STOR_TRANSPORT_GOOD) | 
					
						
							|  |  |  | 			return rc; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		/* hard coded 512 byte sectors as per ATA spec */ | 
					
						
							|  |  |  | 		info->ssize = 0x200; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		US_DEBUGP("usbat_flash_transport: READ_CAPACITY: %ld sectors, %ld bytes per sector\n", | 
					
						
							|  |  |  | 			  info->sectors, info->ssize); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * build the reply | 
					
						
							|  |  |  | 		 * note: must return the sector number of the last sector, | 
					
						
							|  |  |  | 		 * *not* the total number of sectors | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1); | 
					
						
							|  |  |  | 		((__be32 *) ptr)[1] = cpu_to_be32(info->ssize); | 
					
						
							|  |  |  | 		usb_stor_set_xfer_buf(ptr, 8, srb); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_GOOD; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (srb->cmnd[0] == MODE_SELECT_10) { | 
					
						
							|  |  |  | 		US_DEBUGP("usbat_flash_transport:  Gah! MODE_SELECT_10.\n"); | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (srb->cmnd[0] == READ_10) { | 
					
						
							|  |  |  | 		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | | 
					
						
							|  |  |  | 				((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5])); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		US_DEBUGP("usbat_flash_transport:  READ_10: read block 0x%04lx  count %ld\n", block, blocks); | 
					
						
							|  |  |  | 		return usbat_flash_read_data(us, info, block, blocks); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (srb->cmnd[0] == READ_12) { | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * I don't think we'll ever see a READ_12 but support it anyway | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | | 
					
						
							|  |  |  | 		        ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5])); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | | 
					
						
							|  |  |  | 		         ((u32)(srb->cmnd[8]) <<  8) | ((u32)(srb->cmnd[9])); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		US_DEBUGP("usbat_flash_transport: READ_12: read block 0x%04lx  count %ld\n", block, blocks); | 
					
						
							|  |  |  | 		return usbat_flash_read_data(us, info, block, blocks); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (srb->cmnd[0] == WRITE_10) { | 
					
						
							|  |  |  | 		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | | 
					
						
							|  |  |  | 		        ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5])); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		US_DEBUGP("usbat_flash_transport: WRITE_10: write block 0x%04lx  count %ld\n", block, blocks); | 
					
						
							|  |  |  | 		return usbat_flash_write_data(us, info, block, blocks); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (srb->cmnd[0] == WRITE_12) { | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * I don't think we'll ever see a WRITE_12 but support it anyway | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | | 
					
						
							|  |  |  | 		        ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5])); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | | 
					
						
							|  |  |  | 		         ((u32)(srb->cmnd[8]) <<  8) | ((u32)(srb->cmnd[9])); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		US_DEBUGP("usbat_flash_transport: WRITE_12: write block 0x%04lx  count %ld\n", block, blocks); | 
					
						
							|  |  |  | 		return usbat_flash_write_data(us, info, block, blocks); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (srb->cmnd[0] == TEST_UNIT_READY) { | 
					
						
							|  |  |  | 		US_DEBUGP("usbat_flash_transport: TEST_UNIT_READY.\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		rc = usbat_flash_check_media(us, info); | 
					
						
							|  |  |  | 		if (rc != USB_STOR_TRANSPORT_GOOD) | 
					
						
							|  |  |  | 			return rc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return usbat_check_status(us); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (srb->cmnd[0] == REQUEST_SENSE) { | 
					
						
							|  |  |  | 		US_DEBUGP("usbat_flash_transport: REQUEST_SENSE.\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		memset(ptr, 0, 18); | 
					
						
							|  |  |  | 		ptr[0] = 0xF0; | 
					
						
							|  |  |  | 		ptr[2] = info->sense_key; | 
					
						
							|  |  |  | 		ptr[7] = 11; | 
					
						
							|  |  |  | 		ptr[12] = info->sense_asc; | 
					
						
							|  |  |  | 		ptr[13] = info->sense_ascq; | 
					
						
							|  |  |  | 		usb_stor_set_xfer_buf(ptr, 18, srb); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_GOOD; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { | 
					
						
							| 
									
										
										
										
											2005-09-30 12:49:36 +01:00
										 |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * sure.  whatever.  not like we can stop the user from popping | 
					
						
							|  |  |  | 		 * the media out of the device (no locking doors, etc) | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		return USB_STOR_TRANSPORT_GOOD; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	US_DEBUGP("usbat_flash_transport: Gah! Unknown command: %d (0x%x)\n", | 
					
						
							|  |  |  | 			  srb->cmnd[0], srb->cmnd[0]); | 
					
						
							|  |  |  | 	info->sense_key = 0x05; | 
					
						
							|  |  |  | 	info->sense_asc = 0x20; | 
					
						
							|  |  |  | 	info->sense_ascq = 0x00; | 
					
						
							|  |  |  | 	return USB_STOR_TRANSPORT_FAILED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Default transport function. Attempts to detect which transport function | 
					
						
							|  |  |  |  * should be called, makes it the new default, and calls it. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This function should never be called. Our usbat_init() function detects the | 
					
						
							|  |  |  |  * device type and changes the us->transport ptr to the transport function | 
					
						
							|  |  |  |  * relevant to the device. | 
					
						
							|  |  |  |  * However, we'll support this impossible(?) case anyway. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | int usbat_transport(struct scsi_cmnd *srb, struct us_data *us) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct usbat_info *info = (struct usbat_info*) (us->extra); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (usbat_set_transport(us, info)) | 
					
						
							|  |  |  | 		return USB_STOR_TRANSPORT_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return us->transport(srb, us);	 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 |