📄 isd200.c
字号:
/* Transport & Protocol Driver for In-System Design, Inc. ISD200 ASIC * * $Id: isd200.c,v 1.14 2002/02/25 00:40:13 mdharm Exp $ * * Current development and maintenance: * (C) 2001-2002 Bj鰎n Stenberg (bjorn@haxx.se) * * Developed with the assistance of: * (C) 2002 Alan Stern <stern@rowland.org> * * Initial work: * (C) 2000 In-System Design, Inc. (support@in-system.com) * * The ISD200 ASIC does not natively support ATA devices. The chip * does implement an interface, the ATA Command Block (ATACB) which provides * a means of passing ATA commands and ATA register accesses to a device. * * 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. * * History: * * 2001-02-24: Removed lots of duplicate code and simplified the structure. * (bjorn@haxx.se) * 2002-01-16: Fixed endianness bug so it works on the ppc arch. * (Luc Saillard <luc@saillard.org>) * 2002-01-17: All bitfields removed. * (bjorn@haxx.se) *//* Include files */#include "transport.h"#include "protocol.h"#include "usb.h"#include "debug.h"#include "scsiglue.h"#include "isd200.h"#include <linux/sched.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/hdreg.h>#include <linux/ide.h>/* Timeout defines (in Seconds) */#define ISD200_ENUM_BSY_TIMEOUT 35#define ISD200_ENUM_DETECT_TIMEOUT 30#define ISD200_DEFAULT_TIMEOUT 30/* device flags */#define DF_ATA_DEVICE 0x0001#define DF_MEDIA_STATUS_ENABLED 0x0002#define DF_REMOVABLE_MEDIA 0x0004/* capability bit definitions */#define CAPABILITY_DMA 0x01#define CAPABILITY_LBA 0x02/* command_setX bit definitions */#define COMMANDSET_REMOVABLE 0x02#define COMMANDSET_MEDIA_STATUS 0x10/* ATA Vendor Specific defines */#define ATA_ADDRESS_DEVHEAD_STD 0xa0#define ATA_ADDRESS_DEVHEAD_LBA_MODE 0x40 #define ATA_ADDRESS_DEVHEAD_SLAVE 0x10/* Action Select bits */#define ACTION_SELECT_0 0x01#define ACTION_SELECT_1 0x02#define ACTION_SELECT_2 0x04#define ACTION_SELECT_3 0x08#define ACTION_SELECT_4 0x10#define ACTION_SELECT_5 0x20#define ACTION_SELECT_6 0x40#define ACTION_SELECT_7 0x80/* Register Select bits */#define REG_ALTERNATE_STATUS 0x01#define REG_DEVICE_CONTROL 0x01#define REG_ERROR 0x02#define REG_FEATURES 0x02#define REG_SECTOR_COUNT 0x04#define REG_SECTOR_NUMBER 0x08#define REG_CYLINDER_LOW 0x10#define REG_CYLINDER_HIGH 0x20#define REG_DEVICE_HEAD 0x40#define REG_STATUS 0x80#define REG_COMMAND 0x80/* ATA drive control definitions */#define ATA_DC_DISABLE_INTERRUPTS 0x02#define ATA_DC_RESET_CONTROLLER 0x04#define ATA_DC_REENABLE_CONTROLLER 0x00/* * General purpose return codes */ #define ISD200_ERROR -1#define ISD200_GOOD 0/* * Transport return codes */#define ISD200_TRANSPORT_GOOD 0 /* Transport good, command good */#define ISD200_TRANSPORT_FAILED 1 /* Transport good, command failed */#define ISD200_TRANSPORT_ERROR 2 /* Transport bad (i.e. device dead) */#define ISD200_TRANSPORT_ABORTED 3 /* Transport aborted */#define ISD200_TRANSPORT_SHORT 4 /* Transport short *//* driver action codes */#define ACTION_READ_STATUS 0#define ACTION_RESET 1#define ACTION_REENABLE 2#define ACTION_SOFT_RESET 3#define ACTION_ENUM 4#define ACTION_IDENTIFY 5/* * ata_cdb struct */union ata_cdb { struct { unsigned char SignatureByte0; unsigned char SignatureByte1; unsigned char ActionSelect; unsigned char RegisterSelect; unsigned char TransferBlockSize; unsigned char WriteData3F6; unsigned char WriteData1F1; unsigned char WriteData1F2; unsigned char WriteData1F3; unsigned char WriteData1F4; unsigned char WriteData1F5; unsigned char WriteData1F6; unsigned char WriteData1F7; unsigned char Reserved[3]; } generic; struct { unsigned char SignatureByte0; unsigned char SignatureByte1; unsigned char ActionSelect; unsigned char RegisterSelect; unsigned char TransferBlockSize; unsigned char AlternateStatusByte; unsigned char ErrorByte; unsigned char SectorCountByte; unsigned char SectorNumberByte; unsigned char CylinderLowByte; unsigned char CylinderHighByte; unsigned char DeviceHeadByte; unsigned char StatusByte; unsigned char Reserved[3]; } read; struct { unsigned char SignatureByte0; unsigned char SignatureByte1; unsigned char ActionSelect; unsigned char RegisterSelect; unsigned char TransferBlockSize; unsigned char DeviceControlByte; unsigned char FeaturesByte; unsigned char SectorCountByte; unsigned char SectorNumberByte; unsigned char CylinderLowByte; unsigned char CylinderHighByte; unsigned char DeviceHeadByte; unsigned char CommandByte; unsigned char Reserved[3]; } write;};/* * Inquiry data structure. This is the data returned from the target * after it receives an inquiry. * * This structure may be extended by the number of bytes specified * in the field AdditionalLength. The defined size constant only * includes fields through ProductRevisionLevel. *//* * DeviceType field */#define DIRECT_ACCESS_DEVICE 0x00 /* disks */#define DEVICE_REMOVABLE 0x80struct inquiry_data { unsigned char DeviceType; unsigned char DeviceTypeModifier; unsigned char Versions; unsigned char Format; unsigned char AdditionalLength; unsigned char Reserved[2]; unsigned char Capability; unsigned char VendorId[8]; unsigned char ProductId[16]; unsigned char ProductRevisionLevel[4]; unsigned char VendorSpecific[20]; unsigned char Reserved3[40];} __attribute__ ((packed));/* * INQUIRY data buffer size */#define INQUIRYDATABUFFERSIZE 36/* * ISD200 CONFIG data struct */#define ATACFG_TIMING 0x0f#define ATACFG_ATAPI_RESET 0x10#define ATACFG_MASTER 0x20#define ATACFG_BLOCKSIZE 0xa0#define ATACFGE_LAST_LUN 0x07#define ATACFGE_DESC_OVERRIDE 0x08#define ATACFGE_STATE_SUSPEND 0x10#define ATACFGE_SKIP_BOOT 0x20#define ATACFGE_CONF_DESC2 0x40#define ATACFGE_INIT_STATUS 0x80#define CFG_CAPABILITY_SRST 0x01struct isd200_config { unsigned char EventNotification; unsigned char ExternalClock; unsigned char ATAInitTimeout; unsigned char ATAConfig; unsigned char ATAMajorCommand; unsigned char ATAMinorCommand; unsigned char ATAExtraConfig; unsigned char Capability;}__attribute__ ((packed));/* * ISD200 driver information struct */struct isd200_info { struct inquiry_data InquiryData; struct hd_driveid drive; struct isd200_config ConfigData; unsigned char ATARegs[8]; unsigned char DeviceHead; unsigned char DeviceFlags; /* maximum number of LUNs supported */ unsigned char MaxLUNs;};/* * Read Capacity Data - returned in Big Endian format */struct read_capacity_data { unsigned long LogicalBlockAddress; unsigned long BytesPerBlock;};/* * Read Block Limits Data - returned in Big Endian format * This structure returns the maximum and minimum block * size for a TAPE device. */struct read_block_limits { unsigned char Reserved; unsigned char BlockMaximumSize[3]; unsigned char BlockMinimumSize[2];};/* * Sense Data Format */#define SENSE_ERRCODE 0x7f#define SENSE_ERRCODE_VALID 0x80#define SENSE_FLAG_SENSE_KEY 0x0f#define SENSE_FLAG_BAD_LENGTH 0x20#define SENSE_FLAG_END_OF_MEDIA 0x40#define SENSE_FLAG_FILE_MARK 0x80struct sense_data { unsigned char ErrorCode; unsigned char SegmentNumber; unsigned char Flags; unsigned char Information[4]; unsigned char AdditionalSenseLength; unsigned char CommandSpecificInformation[4]; unsigned char AdditionalSenseCode; unsigned char AdditionalSenseCodeQualifier; unsigned char FieldReplaceableUnitCode; unsigned char SenseKeySpecific[3];} __attribute__ ((packed));/* * Default request sense buffer size */#define SENSE_BUFFER_SIZE 18/*********************************************************************** * Helper routines ***********************************************************************//************************************************************************** * isd200_build_sense * * Builds an artificial sense buffer to report the results of a * failed command. * * RETURNS: * void */ void isd200_build_sense(struct us_data *us, Scsi_Cmnd *srb){ struct isd200_info *info = (struct isd200_info *)us->extra; struct sense_data *buf = (struct sense_data *) &srb->sense_buffer[0]; unsigned char error = info->ATARegs[IDE_ERROR_OFFSET]; if(error & MC_ERR) { buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; buf->AdditionalSenseLength = 0xb; buf->Flags = UNIT_ATTENTION; buf->AdditionalSenseCode = 0; buf->AdditionalSenseCodeQualifier = 0; } else if(error & MCR_ERR) { buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; buf->AdditionalSenseLength = 0xb; buf->Flags = UNIT_ATTENTION; buf->AdditionalSenseCode = 0; buf->AdditionalSenseCodeQualifier = 0; } else if(error & TRK0_ERR) { buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; buf->AdditionalSenseLength = 0xb; buf->Flags = NOT_READY; buf->AdditionalSenseCode = 0; buf->AdditionalSenseCodeQualifier = 0; } else if(error & ECC_ERR) { buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; buf->AdditionalSenseLength = 0xb; buf->Flags = DATA_PROTECT; buf->AdditionalSenseCode = 0; buf->AdditionalSenseCodeQualifier = 0; } else { buf->ErrorCode = 0; buf->AdditionalSenseLength = 0; buf->Flags = 0; buf->AdditionalSenseCode = 0; buf->AdditionalSenseCodeQualifier = 0; }}/*********************************************************************** * Data transfer routines ***********************************************************************//************************************************************************** * Transfer one SCSI scatter-gather buffer via bulk transfer * * Note that this function is necessary because we want the ability to * use scatter-gather memory. Good performance is achieved by a combination * of scatter-gather and clustering (which makes each chunk bigger). * * Note that the lower layer will always retry when a NAK occurs, up to the * timeout limit. Thus we don't have to worry about it for individual * packets. */static int isd200_transfer_partial( struct us_data *us, unsigned char dataDirection, char *buf, int length ){ int result; int partial; int pipe; /* calculate the appropriate pipe information */ if (dataDirection == SCSI_DATA_READ) pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); else pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); /* transfer the data */ US_DEBUGP("isd200_transfer_partial(): xfer %d bytes\n", length); result = usb_stor_bulk_msg(us, buf, pipe, length, &partial); US_DEBUGP("usb_stor_bulk_msg() returned %d xferred %d/%d\n", result, partial, length); /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); usb_stor_clear_halt(us, pipe); } /* did we send all the data? */ if (partial == length) { US_DEBUGP("isd200_transfer_partial(): transfer complete\n"); return ISD200_TRANSPORT_GOOD; } /* uh oh... we have an error code, so something went wrong. */ if (result) { /* NAK - that means we've retried a few times already */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -