📄 isd200.c
字号:
/* Transport & Protocol Driver for In-System Design, Inc. ISD200 ASIC * * $Id: isd200.c,v 1.16 2002/04/22 03:39:43 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: * * 2002-10-19: Removed the specialized transfer routines. * (Alan Stern <stern@rowland.harvard.edu>) * 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/jiffies.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 error definitions not in <linux/hdreg.h> */#define ATA_ERROR_MEDIA_CHANGE 0x20/* ATA command definitions not in <linux/hdreg.h> */#define ATA_COMMAND_GET_MEDIA_STATUS 0xDA#define ATA_COMMAND_MEDIA_EJECT 0xED/* 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) *//* 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 *id; struct isd200_config ConfigData; unsigned char *RegsBuf; unsigned char ATARegs[8]; unsigned char DeviceHead; unsigned char DeviceFlags; /* maximum number of LUNs supported */ unsigned char MaxLUNs; struct scsi_cmnd srb;};/* * 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 */static 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 & ATA_ERROR_MEDIA_CHANGE) { 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; }}/*********************************************************************** * Transport routines ***********************************************************************//************************************************************************** * isd200_action * * Routine for sending commands to the isd200 * * RETURNS: * ISD status code */static int isd200_action( struct us_data *us, int action, void* pointer, int value ){ union ata_cdb ata; struct scsi_device srb_dev; struct isd200_info *info = (struct isd200_info *)us->extra; struct scsi_cmnd *srb = &info->srb; int status; memset(&ata, 0, sizeof(ata)); memset(&srb_dev, 0, sizeof(srb_dev)); srb->device = &srb_dev; ++srb->serial_number; ata.generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ata.generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ata.generic.TransferBlockSize = 1; switch ( action ) { case ACTION_READ_STATUS: US_DEBUGP(" isd200_action(READ_STATUS)\n"); ata.generic.ActionSelect = ACTION_SELECT_0|ACTION_SELECT_2; ata.generic.RegisterSelect = REG_CYLINDER_LOW | REG_CYLINDER_HIGH | REG_STATUS | REG_ERROR; srb->sc_data_direction = SCSI_DATA_READ; srb->request_buffer = pointer; srb->request_bufflen = value; break; case ACTION_ENUM: US_DEBUGP(" isd200_action(ENUM,0x%02x)\n",value); ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| ACTION_SELECT_3|ACTION_SELECT_4| ACTION_SELECT_5; ata.generic.RegisterSelect = REG_DEVICE_HEAD; ata.write.DeviceHeadByte = value; srb->sc_data_direction = SCSI_DATA_NONE; break; case ACTION_RESET: US_DEBUGP(" isd200_action(RESET)\n"); ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| ACTION_SELECT_3|ACTION_SELECT_4; ata.generic.RegisterSelect = REG_DEVICE_CONTROL; ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER; srb->sc_data_direction = SCSI_DATA_NONE; break; case ACTION_REENABLE: US_DEBUGP(" isd200_action(REENABLE)\n"); ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| ACTION_SELECT_3|ACTION_SELECT_4; ata.generic.RegisterSelect = REG_DEVICE_CONTROL; ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER; srb->sc_data_direction = SCSI_DATA_NONE; break; case ACTION_SOFT_RESET: US_DEBUGP(" isd200_action(SOFT_RESET)\n"); ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_5; ata.generic.RegisterSelect = REG_DEVICE_HEAD | REG_COMMAND; ata.write.DeviceHeadByte = info->DeviceHead; ata.write.CommandByte = WIN_SRST; srb->sc_data_direction = SCSI_DATA_NONE; break; case ACTION_IDENTIFY: US_DEBUGP(" isd200_action(IDENTIFY)\n"); ata.generic.RegisterSelect = REG_COMMAND; ata.write.CommandByte = WIN_IDENTIFY; srb->sc_data_direction = SCSI_DATA_READ; srb->request_buffer = (void *) info->id; srb->request_bufflen = sizeof(struct hd_driveid); break; default: US_DEBUGP("Error: Undefined action %d\n",action);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -