// SPDX-License-Identifier: GPL-2.0-or-later /* * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters * * Copyright (c) 1995-2000 Advanced System Products, Inc. * Copyright (c) 2000-2001 ConnectCom Solutions, Inc. * Copyright (c) 2007 Matthew Wilcox <matthew@wil.cx> * Copyright (c) 2014 Hannes Reinecke <hare@suse.de> * All Rights Reserved.
*/
/* * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys) * changed its name to ConnectCom Solutions, Inc. * On June 18, 2001 Initio Corp. acquired ConnectCom's SCSI assets
*/
/* The narrow chip only supports a limited selection of transfer rates. * These are encoded in the range 0..7 or 0..15 depending whether the chip * is Ultra-capable or not. These tables let us convert from one to the other.
*/ staticconstunsignedchar asc_syn_xfer_period[8] = {
25, 30, 35, 40, 50, 60, 70, 85
};
/* * These macros keep the chip SCSI id bitfields in board order. C bitfields * aren't portable between big and little-endian platforms so they are not used.
*/
/* * Define total number of simultaneous maximum element scatter-gather * request blocks per wide adapter. ASC_DEF_MAX_HOST_QNG (253) is the * maximum number of outstanding commands per wide host adapter. Each * command uses one or more ADV_SG_BLOCK each with 15 scatter-gather * elements. Allow each command to have at least one ADV_SG_BLOCK structure. * This allows about 15 commands to have the maximum 17 ADV_SG_BLOCK * structures or 255 scatter-gather elements.
*/ #define ADV_TOT_SG_BLOCK ASC_DEF_MAX_HOST_QNG
/* * Define maximum number of scatter-gather elements per request.
*/ #define ADV_MAX_SG_LIST 255 #define NO_OF_SG_PER_BLOCK 15
#define ADV_EEP_DVC_CFG_BEGIN (0x00) #define ADV_EEP_DVC_CFG_END (0x15) #define ADV_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */ #define ADV_EEP_MAX_WORD_ADDR (0x1E)
#define ADV_EEP_DELAY_MS 100
#define ADV_EEPROM_BIG_ENDIAN 0x8000 /* EEPROM Bit 15 */ #define ADV_EEPROM_BIOS_ENABLE 0x4000 /* EEPROM Bit 14 */ /* * For the ASC3550 Bit 13 is Termination Polarity control bit. * For later ICs Bit 13 controls whether the CIS (Card Information * Service Section) is loaded from EEPROM.
*/ #define ADV_EEPROM_TERM_POL 0x2000 /* EEPROM Bit 13 */ #define ADV_EEPROM_CIS_LD 0x2000 /* EEPROM Bit 13 */ /* * ASC38C1600 Bit 11 * * If EEPROM Bit 11 is 0 for Function 0, then Function 0 will specify * INT A in the PCI Configuration Space Int Pin field. If it is 1, then * Function 0 will specify INT B. * * If EEPROM Bit 11 is 0 for Function 1, then Function 1 will specify * INT B in the PCI Configuration Space Int Pin field. If it is 1, then * Function 1 will specify INT A.
*/ #define ADV_EEPROM_INTAB 0x0800 /* EEPROM Bit 11 */
typedefstruct adveep_3550_config { /* Word Offset, Description */
ushort cfg_lsw; /* 00 power up initialization */ /* bit 13 set - Term Polarity Control */ /* bit 14 set - BIOS Enable */ /* bit 15 set - Big Endian Mode */
ushort cfg_msw; /* 01 unused */
ushort disc_enable; /* 02 disconnect enable */
ushort wdtr_able; /* 03 Wide DTR able */
ushort sdtr_able; /* 04 Synchronous DTR able */
ushort start_motor; /* 05 send start up motor */
ushort tagqng_able; /* 06 tag queuing able */
ushort bios_scan; /* 07 BIOS device control */
ushort scam_tolerant; /* 08 no scam */
uchar adapter_scsi_id; /* 09 Host Adapter ID */
uchar bios_boot_delay; /* power up wait */
uchar scsi_reset_delay; /* 10 reset delay */
uchar bios_id_lun; /* first boot device scsi id & lun */ /* high nibble is lun */ /* low nibble is scsi id */
uchar termination; /* 11 0 - automatic */ /* 1 - low off / high off */ /* 2 - low off / high on */ /* 3 - low on / high on */ /* There is no low on / high off */
uchar reserved1; /* reserved byte (not used) */
ushort bios_ctrl; /* 12 BIOS control bits */ /* bit 0 BIOS don't act as initiator. */ /* bit 1 BIOS > 1 GB support */ /* bit 2 BIOS > 2 Disk Support */ /* bit 3 BIOS don't support removables */ /* bit 4 BIOS support bootable CD */ /* bit 5 BIOS scan enabled */ /* bit 6 BIOS support multiple LUNs */ /* bit 7 BIOS display of message */ /* bit 8 SCAM disabled */ /* bit 9 Reset SCSI bus during init. */ /* bit 10 */ /* bit 11 No verbose initialization. */ /* bit 12 SCSI parity enabled */ /* bit 13 */ /* bit 14 */ /* bit 15 */
ushort ultra_able; /* 13 ULTRA speed able */
ushort reserved2; /* 14 reserved */
uchar max_host_qng; /* 15 maximum host queuing */
uchar max_dvc_qng; /* maximum per device queuing */
ushort dvc_cntl; /* 16 control bit for driver */
ushort bug_fix; /* 17 control bit for bug fix */
ushort serial_number_word1; /* 18 Board serial number word 1 */
ushort serial_number_word2; /* 19 Board serial number word 2 */
ushort serial_number_word3; /* 20 Board serial number word 3 */
ushort check_sum; /* 21 EEP check sum */
uchar oem_name[16]; /* 22 OEM name */
ushort dvc_err_code; /* 30 last device driver error code */
ushort adv_err_code; /* 31 last uc and Adv Lib error code */
ushort adv_err_addr; /* 32 last uc error address */
ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
ushort saved_adv_err_addr; /* 35 saved last uc error address */
ushort num_of_err; /* 36 number of error */
} ADVEEP_3550_CONFIG;
typedefstruct adveep_38C0800_config { /* Word Offset, Description */
ushort cfg_lsw; /* 00 power up initialization */ /* bit 13 set - Load CIS */ /* bit 14 set - BIOS Enable */ /* bit 15 set - Big Endian Mode */
ushort cfg_msw; /* 01 unused */
ushort disc_enable; /* 02 disconnect enable */
ushort wdtr_able; /* 03 Wide DTR able */
ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
ushort start_motor; /* 05 send start up motor */
ushort tagqng_able; /* 06 tag queuing able */
ushort bios_scan; /* 07 BIOS device control */
ushort scam_tolerant; /* 08 no scam */
uchar adapter_scsi_id; /* 09 Host Adapter ID */
uchar bios_boot_delay; /* power up wait */
uchar scsi_reset_delay; /* 10 reset delay */
uchar bios_id_lun; /* first boot device scsi id & lun */ /* high nibble is lun */ /* low nibble is scsi id */
uchar termination_se; /* 11 0 - automatic */ /* 1 - low off / high off */ /* 2 - low off / high on */ /* 3 - low on / high on */ /* There is no low on / high off */
uchar termination_lvd; /* 11 0 - automatic */ /* 1 - low off / high off */ /* 2 - low off / high on */ /* 3 - low on / high on */ /* There is no low on / high off */
ushort bios_ctrl; /* 12 BIOS control bits */ /* bit 0 BIOS don't act as initiator. */ /* bit 1 BIOS > 1 GB support */ /* bit 2 BIOS > 2 Disk Support */ /* bit 3 BIOS don't support removables */ /* bit 4 BIOS support bootable CD */ /* bit 5 BIOS scan enabled */ /* bit 6 BIOS support multiple LUNs */ /* bit 7 BIOS display of message */ /* bit 8 SCAM disabled */ /* bit 9 Reset SCSI bus during init. */ /* bit 10 */ /* bit 11 No verbose initialization. */ /* bit 12 SCSI parity enabled */ /* bit 13 */ /* bit 14 */ /* bit 15 */
ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
uchar max_host_qng; /* 15 maximum host queueing */
uchar max_dvc_qng; /* maximum per device queuing */
ushort dvc_cntl; /* 16 control bit for driver */
ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
ushort serial_number_word1; /* 18 Board serial number word 1 */
ushort serial_number_word2; /* 19 Board serial number word 2 */
ushort serial_number_word3; /* 20 Board serial number word 3 */
ushort check_sum; /* 21 EEP check sum */
uchar oem_name[16]; /* 22 OEM name */
ushort dvc_err_code; /* 30 last device driver error code */
ushort adv_err_code; /* 31 last uc and Adv Lib error code */
ushort adv_err_addr; /* 32 last uc error address */
ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
ushort saved_adv_err_addr; /* 35 saved last uc error address */
ushort reserved36; /* 36 reserved */
ushort reserved37; /* 37 reserved */
ushort reserved38; /* 38 reserved */
ushort reserved39; /* 39 reserved */
ushort reserved40; /* 40 reserved */
ushort reserved41; /* 41 reserved */
ushort reserved42; /* 42 reserved */
ushort reserved43; /* 43 reserved */
ushort reserved44; /* 44 reserved */
ushort reserved45; /* 45 reserved */
ushort reserved46; /* 46 reserved */
ushort reserved47; /* 47 reserved */
ushort reserved48; /* 48 reserved */
ushort reserved49; /* 49 reserved */
ushort reserved50; /* 50 reserved */
ushort reserved51; /* 51 reserved */
ushort reserved52; /* 52 reserved */
ushort reserved53; /* 53 reserved */
ushort reserved54; /* 54 reserved */
ushort reserved55; /* 55 reserved */
ushort cisptr_lsw; /* 56 CIS PTR LSW */
ushort cisprt_msw; /* 57 CIS PTR MSW */
ushort subsysvid; /* 58 SubSystem Vendor ID */
ushort subsysid; /* 59 SubSystem ID */
ushort reserved60; /* 60 reserved */
ushort reserved61; /* 61 reserved */
ushort reserved62; /* 62 reserved */
ushort reserved63; /* 63 reserved */
} ADVEEP_38C0800_CONFIG;
typedefstruct adveep_38C1600_config { /* Word Offset, Description */
ushort cfg_lsw; /* 00 power up initialization */ /* bit 11 set - Func. 0 INTB, Func. 1 INTA */ /* clear - Func. 0 INTA, Func. 1 INTB */ /* bit 13 set - Load CIS */ /* bit 14 set - BIOS Enable */ /* bit 15 set - Big Endian Mode */
ushort cfg_msw; /* 01 unused */
ushort disc_enable; /* 02 disconnect enable */
ushort wdtr_able; /* 03 Wide DTR able */
ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
ushort start_motor; /* 05 send start up motor */
ushort tagqng_able; /* 06 tag queuing able */
ushort bios_scan; /* 07 BIOS device control */
ushort scam_tolerant; /* 08 no scam */
uchar adapter_scsi_id; /* 09 Host Adapter ID */
uchar bios_boot_delay; /* power up wait */
uchar scsi_reset_delay; /* 10 reset delay */
uchar bios_id_lun; /* first boot device scsi id & lun */ /* high nibble is lun */ /* low nibble is scsi id */
uchar termination_se; /* 11 0 - automatic */ /* 1 - low off / high off */ /* 2 - low off / high on */ /* 3 - low on / high on */ /* There is no low on / high off */
uchar termination_lvd; /* 11 0 - automatic */ /* 1 - low off / high off */ /* 2 - low off / high on */ /* 3 - low on / high on */ /* There is no low on / high off */
ushort bios_ctrl; /* 12 BIOS control bits */ /* bit 0 BIOS don't act as initiator. */ /* bit 1 BIOS > 1 GB support */ /* bit 2 BIOS > 2 Disk Support */ /* bit 3 BIOS don't support removables */ /* bit 4 BIOS support bootable CD */ /* bit 5 BIOS scan enabled */ /* bit 6 BIOS support multiple LUNs */ /* bit 7 BIOS display of message */ /* bit 8 SCAM disabled */ /* bit 9 Reset SCSI bus during init. */ /* bit 10 Basic Integrity Checking disabled */ /* bit 11 No verbose initialization. */ /* bit 12 SCSI parity enabled */ /* bit 13 AIPP (Asyn. Info. Ph. Prot.) dis. */ /* bit 14 */ /* bit 15 */
ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
uchar max_host_qng; /* 15 maximum host queueing */
uchar max_dvc_qng; /* maximum per device queuing */
ushort dvc_cntl; /* 16 control bit for driver */
ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
ushort serial_number_word1; /* 18 Board serial number word 1 */
ushort serial_number_word2; /* 19 Board serial number word 2 */
ushort serial_number_word3; /* 20 Board serial number word 3 */
ushort check_sum; /* 21 EEP check sum */
uchar oem_name[16]; /* 22 OEM name */
ushort dvc_err_code; /* 30 last device driver error code */
ushort adv_err_code; /* 31 last uc and Adv Lib error code */
ushort adv_err_addr; /* 32 last uc error address */
ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
ushort saved_adv_err_addr; /* 35 saved last uc error address */
ushort reserved36; /* 36 reserved */
ushort reserved37; /* 37 reserved */
ushort reserved38; /* 38 reserved */
ushort reserved39; /* 39 reserved */
ushort reserved40; /* 40 reserved */
ushort reserved41; /* 41 reserved */
ushort reserved42; /* 42 reserved */
ushort reserved43; /* 43 reserved */
ushort reserved44; /* 44 reserved */
ushort reserved45; /* 45 reserved */
ushort reserved46; /* 46 reserved */
ushort reserved47; /* 47 reserved */
ushort reserved48; /* 48 reserved */
ushort reserved49; /* 49 reserved */
ushort reserved50; /* 50 reserved */
ushort reserved51; /* 51 reserved */
ushort reserved52; /* 52 reserved */
ushort reserved53; /* 53 reserved */
ushort reserved54; /* 54 reserved */
ushort reserved55; /* 55 reserved */
ushort cisptr_lsw; /* 56 CIS PTR LSW */
ushort cisprt_msw; /* 57 CIS PTR MSW */
ushort subsysvid; /* 58 SubSystem Vendor ID */
ushort subsysid; /* 59 SubSystem ID */
ushort reserved60; /* 60 reserved */
ushort reserved61; /* 61 reserved */
ushort reserved62; /* 62 reserved */
ushort reserved63; /* 63 reserved */
} ADVEEP_38C1600_CONFIG;
/* * XXX - Since ASC38C1600 Rev.3 has a local RAM failure issue, there is * a special 16K Adv Library and Microcode version. After the issue is * resolved, should restore 32K support. * * #define ADV_38C1600_MEMSIZE 0x8000L * 32 KB Internal Memory *
*/ #define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */
/* * ASC38C1600 Definitions * * IOPB_PCI_INT_CFG Bit Field Definitions
*/
#define INTAB_LD 0x80 /* Value loaded from EEPROM Bit 11. */
/* * Bit 1 can be set to change the interrupt for the Function to operate in * Totem Pole mode. By default Bit 1 is 0 and the interrupt operates in * Open Drain mode. Both functions of the ASC38C1600 must be set to the same * mode, otherwise the operating mode is undefined.
*/ #define TOTEMPOLE 0x02
/* * Bit 0 can be used to change the Int Pin for the Function. The value is * 0 by default for both Functions with Function 0 using INT A and Function * B using INT B. For Function 0 if set, INT B is used. For Function 1 if set, * INT A is used. * * EEPROM Word 0 Bit 11 for each Function may change the initial Int Pin * value specified in the PCI Configuration Space.
*/ #define INTAB 0x01
/* * Microcode Control Flags * * Flags set by the Adv Library in RISC variable 'control_flag' (0x122) * and handled by the microcode.
*/ #define CONTROL_FLAG_IGNORE_PERR 0x0001 /* Ignore DMA Parity Errors */ #define CONTROL_FLAG_ENABLE_AIPP 0x0002 /* Enabled AIPP checking. */
/* * ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format
*/ #define HSHK_CFG_WIDE_XFR 0x8000 #define HSHK_CFG_RATE 0x0F00 #define HSHK_CFG_OFFSET 0x001F
#define ASC_DEF_MAX_HOST_QNG 0xFD /* Max. number of host commands (253) */ #define ASC_DEF_MIN_HOST_QNG 0x10 /* Min. number of host commands (16) */ #define ASC_DEF_MAX_DVC_QNG 0x3F /* Max. number commands per device (63) */ #define ASC_DEF_MIN_DVC_QNG 0x04 /* Min. number commands per device (4) */
#define ASC_QC_DATA_CHECK 0x01 /* Require ASC_QC_DATA_OUT set or clear. */ #define ASC_QC_DATA_OUT 0x02 /* Data out DMA transfer. */ #define ASC_QC_START_MOTOR 0x04 /* Send auto-start motor before request. */ #define ASC_QC_NO_OVERRUN 0x08 /* Don't report overrun. */ #define ASC_QC_FREEZE_TIDQ 0x10 /* Freeze TID queue after request. XXX TBD */
#define ASC_QSC_NO_DISC 0x01 /* Don't allow disconnect for request. */ #define ASC_QSC_NO_TAGMSG 0x02 /* Don't allow tag queuing for request. */ #define ASC_QSC_NO_SYNC 0x04 /* Don't use Synch. transfer on request. */ #define ASC_QSC_NO_WIDE 0x08 /* Don't use Wide transfer on request. */ #define ASC_QSC_REDO_DTR 0x10 /* Renegotiate WDTR/SDTR before request. */ /* * Note: If a Tag Message is to be sent and neither ASC_QSC_HEAD_TAG or * ASC_QSC_ORDERED_TAG is set, then a Simple Tag Message (0x20) is used.
*/ #define ASC_QSC_HEAD_TAG 0x40 /* Use Head Tag Message (0x21). */ #define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */
/* * All fields here are accessed by the board microcode and need to be * little-endian.
*/ typedefstruct adv_carr_t {
__le32 carr_va; /* Carrier Virtual Address */
__le32 carr_pa; /* Carrier Physical Address */
__le32 areq_vpa; /* ADV_SCSI_REQ_Q Virtual or Physical Address */ /* * next_vpa [31:4] Carrier Virtual or Physical Next Pointer * * next_vpa [3:1] Reserved Bits * next_vpa [0] Done Flag set in Response Queue.
*/
__le32 next_vpa;
} ADV_CARR_T;
/* * Mask used to eliminate low 4 bits of carrier 'next_vpa' field.
*/ #define ADV_NEXT_VPA_MASK 0xFFFFFFF0
/* * Each carrier is 64 bytes, and we need three additional * carrier for icq, irq, and the termination carrier.
*/ #define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 3)
#define ADV_CHIP_ASC3550 0x01 /* Ultra-Wide IC */ #define ADV_CHIP_ASC38C0800 0x02 /* Ultra2-Wide/LVD IC */ #define ADV_CHIP_ASC38C1600 0x03 /* Ultra3-Wide/LVD2 IC */
/* * Adapter temporary configuration structure * * This structure can be discarded after initialization. Don't add * fields here needed after initialization. * * Field naming convention: * * *_enable indicates the field enables or disables a feature. The * value of the field is never reset.
*/ typedefstruct adv_dvc_cfg {
ushort disc_enable; /* enable disconnection */
uchar chip_version; /* chip version */
uchar termination; /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */
ushort control_flag; /* Microcode Control Flag */
ushort mcode_date; /* Microcode date */
ushort mcode_version; /* Microcode version */
ushort serial1; /* EEPROM serial number word 1 */
ushort serial2; /* EEPROM serial number word 2 */
ushort serial3; /* EEPROM serial number word 3 */
} ADV_DVC_CFG;
struct adv_dvc_var; struct adv_scsi_req_q;
typedefstruct adv_sg_block {
uchar reserved1;
uchar reserved2;
uchar reserved3;
uchar sg_cnt; /* Valid entries in block. */
__le32 sg_ptr; /* Pointer to next sg block. */ struct {
__le32 sg_addr; /* SG element address. */
__le32 sg_count; /* SG element count. */
} sg_list[NO_OF_SG_PER_BLOCK];
} ADV_SG_BLOCK;
/* * ADV_SCSI_REQ_Q - microcode request structure * * All fields in this structure up to byte 60 are used by the microcode. * The microcode makes assumptions about the size and ordering of fields * in this structure. Do not change the structure definition here without * coordinating the change with the microcode. * * All fields accessed by microcode must be maintained in little_endian * order.
*/ typedefstruct adv_scsi_req_q {
uchar cntl; /* Ucode flags and state (ASC_MC_QC_*). */
uchar target_cmd;
uchar target_id; /* Device target identifier. */
uchar target_lun; /* Device target logical unit number. */
__le32 data_addr; /* Data buffer physical address. */
__le32 data_cnt; /* Data count. Ucode sets to residual. */
__le32 sense_addr;
__le32 carr_pa;
uchar mflag;
uchar sense_len;
uchar cdb_len; /* SCSI CDB length. Must <= 16 bytes. */
uchar scsi_cntl;
uchar done_status; /* Completion status. */
uchar scsi_status; /* SCSI status byte. */
uchar host_status; /* Ucode host status. */
uchar sg_working_ix;
uchar cdb[12]; /* SCSI CDB bytes 0-11. */
__le32 sg_real_addr; /* SG list physical address. */
__le32 scsiq_rptr;
uchar cdb16[4]; /* SCSI CDB bytes 12-15. */
__le32 scsiq_ptr;
__le32 carr_va; /* * End of microcode structure - 60 bytes. The rest of the structure * is used by the Adv Library and ignored by the microcode.
*/
u32 srb_tag;
ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
} ADV_SCSI_REQ_Q;
/* * The following two structures are used to process Wide Board requests. * * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library * and microcode with the ADV_SCSI_REQ_Q field 'srb_tag' set to the * SCSI request tag. The adv_req_t structure 'cmndp' field in turn points * to the Mid-Level SCSI request structure. * * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux * up to 255 scatter-gather elements may be used per request or * ADV_SCSI_REQ_Q. * * Both structures must be 32 byte aligned.
*/ typedefstruct adv_sgblk {
ADV_SG_BLOCK sg_block; /* Sgblock structure. */
dma_addr_t sg_addr; /* Physical address */ struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */
} adv_sgblk_t;
/* * Adapter operation variable structure. * * One structure is required per host adapter. * * Field naming convention: * * *_able indicates both whether a feature should be enabled or disabled * and whether a device is capable of the feature. At initialization * this field may be set, but later if a device is found to be incapable * of the feature, the field is cleared.
*/ typedefstruct adv_dvc_var {
AdvPortAddr iop_base; /* I/O port address */
ushort err_code; /* fatal error code */
ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */
ushort wdtr_able; /* try WDTR for a device */
ushort sdtr_able; /* try SDTR for a device */
ushort ultra_able; /* try SDTR Ultra speed for a device */
ushort sdtr_speed1; /* EEPROM SDTR Speed for TID 0-3 */
ushort sdtr_speed2; /* EEPROM SDTR Speed for TID 4-7 */
ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */
ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */
ushort tagqng_able; /* try tagged queuing with a device */
ushort ppr_able; /* PPR message capable per TID bitmask. */
uchar max_dvc_qng; /* maximum number of tagged commands per device */
ushort start_motor; /* start motor command allowed */
uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */
uchar chip_no; /* should be assigned by caller */
uchar max_host_qng; /* maximum number of Q'ed command allowed */
ushort no_scam; /* scam_tolerant of EEPROM */ struct asc_board *drv_ptr; /* driver pointer to private structure */
uchar chip_scsi_id; /* chip SCSI target ID */
uchar chip_type;
uchar bist_err_code;
ADV_CARR_T *carrier;
ADV_CARR_T *carr_freelist; /* Carrier free list. */
dma_addr_t carrier_addr;
ADV_CARR_T *icq_sp; /* Initiator command queue stopper pointer. */
ADV_CARR_T *irq_sp; /* Initiator response queue stopper pointer. */
ushort carr_pending_cnt; /* Count of pending carriers. */ /* * Note: The following fields will not be used after initialization. The * driver may discard the buffer after initialization is done.
*/
ADV_DVC_CFG *cfg; /* temporary configuration structure */
} ADV_DVC_VAR;
/* Write little-endian double word (4 bytes) to LRAM */ /* Because of unspecified C language ordering don't use auto-increment. */ #define AdvWriteDWordLramNoSwap(iop_base, addr, dword) \
((ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
cpu_to_le16((ushort) ((dword) & 0xFFFF)))), \
(ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \
ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
cpu_to_le16((ushort) ((dword >> 16) & 0xFFFF)))))
/* Read word (2 bytes) from LRAM assuming that the address is already set. */ #define AdvReadWordAutoIncLram(iop_base) \
(ADV_MEM_READW((iop_base) + IOPW_RAM_DATA))
/* Write word (2 bytes) to LRAM assuming that the address is already set. */ #define AdvWriteWordAutoIncLram(iop_base, word) \
(ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
/* * Define macro to check for Condor signature. * * Evaluate to ADV_TRUE if a Condor chip is found the specified port * address 'iop_base'. Otherwise evalue to ADV_FALSE.
*/ #define AdvFindSignature(iop_base) \
(((AdvReadByteRegister((iop_base), IOPB_CHIP_ID_1) == \
ADV_CHIP_ID_BYTE) && \
(AdvReadWordRegister((iop_base), IOPW_CHIP_ID_0) == \
ADV_CHIP_ID_WORD)) ? ADV_TRUE : ADV_FALSE)
/* * Define macro to Return the version number of the chip at 'iop_base'. * * The second parameter 'bus_type' is currently unused.
*/ #define AdvGetChipVersion(iop_base, bus_type) \
AdvReadByteRegister((iop_base), IOPB_CHIP_TYPE_REV)
/* * Abort an SRB in the chip's RISC Memory. The 'srb_tag' argument must * match the ADV_SCSI_REQ_Q 'srb_tag' field. * * If the request has not yet been sent to the device it will simply be * aborted from RISC memory. If the request is disconnected it will be * aborted on reselection by sending an Abort Message to the target ID. * * Return value: * ADV_TRUE(1) - Queue was successfully aborted. * ADV_FALSE(0) - Queue was not found on the active queue list.
*/ #define AdvAbortQueue(asc_dvc, srb_tag) \
AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \
(ADV_DCNT) (srb_tag))
/* * Send a Bus Device Reset Message to the specified target ID. * * All outstanding commands will be purged if sending the * Bus Device Reset Message is successful. * * Return Value: * ADV_TRUE(1) - All requests on the target are purged. * ADV_FALSE(0) - Couldn't issue Bus Device Reset Message; Requests * are not purged.
*/ #define AdvResetDevice(asc_dvc, target_id) \
AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_DEVICE_RESET, \
(ADV_DCNT) (target_id))
/* * SCSI Wide Type definition.
*/ #define ADV_SCSI_BIT_ID_TYPE ushort
/* Return the address that is aligned at the next doubleword >= to 'addr'. */ #define ADV_32BALIGN(addr) (((ulong) (addr) + 0x1F) & ~0x1F)
/* * Total contiguous memory needed for driver SG blocks. * * ADV_MAX_SG_LIST must be defined by a driver. It is the maximum * number of scatter-gather elements the driver supports in a * single request.
*/
/* * asc_prt_hex() * * Print hexadecimal output in 4 byte groupings 32 bytes * or 8 double-words per line.
*/ staticvoid asc_prt_hex(char *f, uchar *s, int l)
{ int i; int j; int k; int m;
printk("%s: (%d bytes)\n", f, l);
for (i = 0; i < l; i += 32) {
/* Display a maximum of 8 double-words per line. */ if ((k = (l - i) / 4) >= 8) {
k = 8;
m = 0;
} else {
m = (l - i) % 4;
}
/* * advansys_info() * * Return suitable for printing on the console with the argument * adapter's configuration information. * * Note: The information line should not exceed ASC_INFO_SIZE bytes, * otherwise the static 'info' array will be overrun.
*/ staticconstchar *advansys_info(struct Scsi_Host *shost)
{ staticchar info[ASC_INFO_SIZE]; struct asc_board *boardp = shost_priv(shost);
ASC_DVC_VAR *asc_dvc_varp;
ADV_DVC_VAR *adv_dvc_varp; char *busname; char *widename = NULL;
if (ASC_NARROW_BOARD(boardp)) {
asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
ASC_DBG(1, "begin\n");
if (asc_dvc_varp->bus_type & ASC_IS_VL) {
busname = "VL";
} elseif (asc_dvc_varp->bus_type & ASC_IS_EISA) {
busname = "EISA";
} elseif (asc_dvc_varp->bus_type & ASC_IS_PCI) { if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
== ASC_IS_PCI_ULTRA) {
busname = "PCI Ultra";
} else {
busname = "PCI";
}
} else {
busname = "?";
shost_printk(KERN_ERR, shost, "unknown bus " "type %d\n", asc_dvc_varp->bus_type);
}
sprintf(info, "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
ASC_VERSION, busname, (ulong)shost->io_port,
(ulong)shost->io_port + ASC_IOADR_GAP - 1,
boardp->irq);
} else { /* * Wide Adapter Information * * Memory-mapped I/O is used instead of I/O space to access * the adapter, but display the I/O Port range. The Memory * I/O address is displayed through the driver /proc file.
*/
adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
widename = "Ultra-Wide";
} elseif (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
widename = "Ultra2-Wide";
} else {
widename = "Ultra3-Wide";
}
sprintf(info, "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base,
(ulong)adv_dvc_varp->iop_base + boardp->asc_n_io_port - 1, boardp->irq);
}
BUG_ON(strlen(info) >= ASC_INFO_SIZE);
ASC_DBG(1, "end\n"); return info;
}
#ifdef CONFIG_PROC_FS
/* * asc_prt_board_devices() * * Print driver information for devices attached to the board.
*/ staticvoid asc_prt_board_devices(struct seq_file *m, struct Scsi_Host *shost)
{ struct asc_board *boardp = shost_priv(shost); int chip_scsi_id; int i;
seq_printf(m, "\nDevice Information for AdvanSys SCSI Host %d:\n",
shost->host_no);
/* * If the BIOS saved a valid signature, then fill in * the BIOS code segment base address.
*/ if (boardp->bios_signature != 0x55AA) {
seq_puts(m, "Disabled or Pre-3.1\n" "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n" "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
} else {
major = (boardp->bios_version >> 12) & 0xF;
minor = (boardp->bios_version >> 8) & 0xF;
letter = (boardp->bios_version & 0xFF);
seq_printf(m, "%d.%d%c\n",
major, minor,
letter >= 26 ? '?' : letter + 'A'); /* * Current available ROM BIOS release is 3.1I for UW * and 3.2I for U2W. This code doesn't differentiate * UW and U2W boards.
*/ if (major < 3 || (major <= 3 && minor < 1) ||
(major <= 3 && minor <= 1 && letter < ('I' - 'A'))) {
seq_puts(m, "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n" "ftp://ftp.connectcom.net/pub\n");
}
}
}
/* * Add serial number to information bar if signature AAh * is found in at bit 15-9 (7 bits) of word 1. * * Serial Number consists fo 12 alpha-numeric digits. * * 1 - Product type (A,B,C,D..) Word0: 15-13 (3 bits) * 2 - MFG Location (A,B,C,D..) Word0: 12-10 (3 bits) * 3-4 - Product ID (0-99) Word0: 9-0 (10 bits) * 5 - Product revision (A-J) Word0: " " * * Signature Word1: 15-9 (7 bits) * 6 - Year (0-9) Word1: 8-6 (3 bits) & Word2: 15 (1 bit) * 7-8 - Week of the year (1-52) Word1: 5-0 (6 bits) * * 9-12 - Serial Number (A001-Z999) Word2: 14-0 (15 bits) * * Note 1: Only production cards will have a serial number. * * Note 2: Signature is most significant 7 bits (0xFE). * * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE.
*/ staticint asc_get_eeprom_string(ushort *serialnum, uchar *cp)
{
ushort w, num;
if ((serialnum[1] & 0xFE00) != ((ushort)0xAA << 8)) { return ASC_FALSE;
} else { /* * First word - 6 digits.
*/
w = serialnum[0];
/* Product type - 1st digit. */ if ((*cp = 'A' + ((w & 0xE000) >> 13)) == 'H') { /* Product type is P=Prototype */
*cp += 0x8;
}
cp++;
/* * Year - 6th digit. * * If bit 15 of third word is set, then the * last digit of the year is greater than 7.
*/ if (serialnum[2] & 0x8000) {
*cp++ = '8' + ((w & 0x1C0) >> 6);
} else {
*cp++ = '0' + ((w & 0x1C0) >> 6);
}
/* Week of year - 7th, 8th digits. */
num = w & 0x003F;
*cp++ = '0' + num / 10;
num %= 10;
*cp++ = '0' + num;
/* * Third word
*/
w = serialnum[2] & 0x7FFF;
/* Serial number - 9th digit. */
*cp++ = 'A' + (w / 1000);
/* 10th, 11th, 12th digits. */
num = w % 1000;
*cp++ = '0' + num / 100;
num %= 100;
*cp++ = '0' + num / 10;
num %= 10;
*cp++ = '0' + num;
seq_printf(m, "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
shost->host_no);
if (asc_get_eeprom_string((ushort *)&ep->adapter_info[0], serialstr)
== ASC_TRUE)
seq_printf(m, " Serial Number: %s\n", serialstr); elseif (ep->adapter_info[5] == 0xBB)
seq_puts(m, " Default Settings Used for EEPROM-less Adapter.\n"); else
seq_puts(m, " Serial Number Signature Not Present.\n");
if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE)
seq_printf(m, " Serial Number: %s\n", serialstr); else
seq_puts(m, " Serial Number Signature Not Present.\n");
/* Current number of commands waiting for the host. */
seq_printf(m, " Total Command Pending: %d\n", v->cur_total_qng);
seq_puts(m, " Command Queuing:"); for (i = 0; i <= ASC_MAX_TID; i++) { if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { continue;
}
seq_printf(m, " %X:%c",
i,
(v->use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
}
/* Current number of commands waiting for a device. */
seq_puts(m, "\n Command Queue Pending:"); for (i = 0; i <= ASC_MAX_TID; i++) { if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { continue;
}
seq_printf(m, " %X:%u", i, v->cur_dvc_qng[i]);
}
/* Current limit on number of commands that can be sent to a device. */
seq_puts(m, "\n Command Queue Limit:"); for (i = 0; i <= ASC_MAX_TID; i++) { if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { continue;
}
seq_printf(m, " %X:%u", i, v->max_dvc_qng[i]);
}
/* Indicate whether the device has returned queue full status. */
seq_puts(m, "\n Command Queue Full:"); for (i = 0; i <= ASC_MAX_TID; i++) { if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { continue;
} if (boardp->queue_full & ADV_TID_TO_TIDMASK(i))
seq_printf(m, " %X:Y-%d",
i, boardp->queue_full_cnt[i]); else
seq_printf(m, " %X:N", i);
}
seq_puts(m, "\n Synchronous Transfer:"); for (i = 0; i <= ASC_MAX_TID; i++) { if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { continue;
}
seq_printf(m, " %X:%c",
i,
(v->sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
}
seq_putc(m, '\n');
for (i = 0; i <= ASC_MAX_TID; i++) {
uchar syn_period_ix;
AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
seq_puts(m, " Transfer Bit Width:"); for (i = 0; i <= ADV_MAX_TID; i++) { if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { continue;
}
/* * advansys_show_info() - /proc/scsi/advansys/{0,1,2,3,...} * * m: seq_file to print into * shost: Scsi_Host * * Return the number of bytes read from or written to a * /proc/scsi/advansys/[0...] file.
*/ staticint
advansys_show_info(struct seq_file *m, struct Scsi_Host *shost)
{ struct asc_board *boardp = shost_priv(shost);
ASC_DBG(1, "begin\n");
/* * User read of /proc/scsi/advansys/[0...] file.
*/
/* * Get board configuration information. * * advansys_info() returns the board string from its own static buffer.
*/ /* Copy board information. */
seq_printf(m, "%s\n", (char *)advansys_info(shost)); /* * Display Wide Board BIOS Information.
*/ if (!ASC_NARROW_BOARD(boardp))
asc_prt_adv_bios(m, shost);
/* * Display driver information for each device attached to the board.
*/
asc_prt_board_devices(m, shost);
/* * Display EEPROM configuration for the board.
*/ if (ASC_NARROW_BOARD(boardp))
asc_prt_asc_board_eeprom(m, shost); else
asc_prt_adv_board_eeprom(m, shost);
/* * Display driver configuration and information for the board.
*/
asc_prt_driver_conf(m, shost);
#ifdef ADVANSYS_STATS /* * Display driver statistics for the board.
*/
asc_prt_board_stats(m, shost); #endif/* ADVANSYS_STATS */
/* * Display Asc Library dynamic configuration information * for the board.
*/ if (ASC_NARROW_BOARD(boardp))
asc_prt_asc_board_info(m, shost); else
asc_prt_adv_board_info(m, shost); return 0;
} #endif/* CONFIG_PROC_FS */
/* * Copy 2 bytes to LRAM. * * The source data is assumed to be in little-endian order in memory * and is maintained in little-endian order when written to LRAM.
*/ staticvoid
AscMemWordCopyPtrToLram(PortAddr iop_base, ushort s_addr, const uchar *s_buffer, int words)
{ int i;
AscSetChipLramAddr(iop_base, s_addr); for (i = 0; i < 2 * words; i += 2) { /* * On a little-endian system the second argument below * produces a little-endian ushort which is written to * LRAM in little-endian order. On a big-endian system * the second argument produces a big-endian ushort which * is "transparently" byte-swapped by outpw() and written * in little-endian order to LRAM.
*/
outpw(iop_base + IOP_RAM_DATA,
((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);
}
}
/* * Copy 4 bytes to LRAM. * * The source data is assumed to be in little-endian order in memory * and is maintained in little-endian order when written to LRAM.
*/ staticvoid
AscMemDWordCopyPtrToLram(PortAddr iop_base,
ushort s_addr, uchar *s_buffer, int dwords)
{ int i;
/* * Copy 2 bytes from LRAM. * * The source data is assumed to be in little-endian order in LRAM * and is maintained in little-endian order when written to memory.
*/ staticvoid
AscMemWordCopyPtrFromLram(PortAddr iop_base,
ushort s_addr, uchar *d_buffer, int words)
{ int i;
ushort word;
AscSetChipLramAddr(iop_base, s_addr); for (i = 0; i < 2 * words; i += 2) {
word = inpw(iop_base + IOP_RAM_DATA);
d_buffer[i] = word & 0xff;
d_buffer[i + 1] = (word >> 8) & 0xff;
}
}
static u32 AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words)
{
u32 sum = 0; int i;
for (i = 0; i < words; i++, s_addr += 2) {
sum += AscReadLramWord(iop_base, s_addr);
} return (sum);
}
staticint AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
{ int i; int warn_code;
PortAddr iop_base;
__le32 phy_addr;
__le32 phy_size; struct asc_board *board = asc_dvc_to_board(asc_dvc);
iop_base = asc_dvc->iop_base;
warn_code = 0; for (i = 0; i <= ASC_MAX_TID; i++) {
AscPutMCodeInitSDTRAtID(iop_base, i,
asc_dvc->cfg->sdtr_period_offset[i]);
}
/* * Load the Microcode * * Write the microcode image to RISC memory starting at address 0. * * The microcode is stored compressed in the following format: * * 254 word (508 byte) table indexed by byte code followed * by the following byte codes: * * 1-Byte Code: * 00: Emit word 0 in table. * 01: Emit word 1 in table. * . * FD: Emit word 253 in table. * * Multi-Byte Code: * FE WW WW: (3 byte code) Word to emit is the next word WW WW. * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW. * * Returns 0 or an error if the checksum doesn't match
*/ staticint AdvLoadMicrocode(AdvPortAddr iop_base, constunsignedchar *buf, int size, int memsize, int chksum)
{ int i, j, end, len = 0;
u32 sum;
AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
for (i = 253 * 2; i < size; i++) { if (buf[i] == 0xff) { unsignedshort word = (buf[i + 3] << 8) | buf[i + 2]; for (j = 0; j < buf[i + 1]; j++) {
AdvWriteWordAutoIncLram(iop_base, word);
len += 2;
}
i += 3;
} elseif (buf[i] == 0xfe) { unsignedshort word = (buf[i + 2] << 8) | buf[i + 1];
AdvWriteWordAutoIncLram(iop_base, word);
i += 2;
len += 2;
} else { unsignedint off = buf[i] * 2; unsignedshort word = (buf[off + 1] << 8) | buf[off];
AdvWriteWordAutoIncLram(iop_base, word);
len += 2;
}
}
end = len;
while (len < memsize) {
AdvWriteWordAutoIncLram(iop_base, 0);
len += 2;
}
/* Verify the microcode checksum. */
sum = 0;
AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
for (len = 0; len < end; len += 2) {
sum += AdvReadWordAutoIncLram(iop_base);
}
for (i = 0; i < carr_num; i++) {
carr_offset = i * sizeof(ADV_CARR_T); /* Get physical address of the carrier 'carrp'. */
carr_paddr = adv_dvc->carrier_addr + carr_offset;
adv_dvc->carrier[i].carr_pa = cpu_to_le32(carr_paddr);
adv_dvc->carrier[i].carr_va = cpu_to_le32(carr_offset);
adv_dvc->carrier[i].areq_vpa = 0;
next_offset = carr_offset + sizeof(ADV_CARR_T); if (i == carr_num)
next_offset = ~0;
adv_dvc->carrier[i].next_vpa = cpu_to_le32(next_offset);
} /* * We cannot have a carrier with 'carr_va' of '0', as * a reference to this carrier would be interpreted as * list termination. * So start at carrier 1 with the freelist.
*/
adv_dvc->carr_freelist = &adv_dvc->carrier[1];
}
static ADV_CARR_T *adv_get_carrier(struct adv_dvc_var *adv_dvc, u32 offset)
{ int index;
BUG_ON(offset > ADV_CARRIER_BUFSIZE);
index = offset / sizeof(ADV_CARR_T); return &adv_dvc->carrier[index];
}
/* * Send an idle command to the chip and wait for completion. * * Command completion is polled for once per microsecond. * * The function can be called from anywhere including an interrupt handler. * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical() * functions to prevent reentrancy. * * Return Values: * ADV_TRUE - command completed successfully * ADV_FALSE - command failed * ADV_ERROR - command timed out
*/ staticint
AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
ushort idle_cmd, u32 idle_cmd_parameter)
{ int result, i, j;
AdvPortAddr iop_base;
iop_base = asc_dvc->iop_base;
/* * Clear the idle command status which is set by the microcode * to a non-zero value to indicate when the command is completed. * The non-zero result is one of the IDLE_CMD_STATUS_* values
*/
AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0);
/* * Write the idle command value after the idle command parameter * has been written to avoid a race condition. If the order is not * followed, the microcode may process the idle command before the * parameters have been written to LRAM.
*/
AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
cpu_to_le32(idle_cmd_parameter));
AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
/* * Tickle the RISC to tell it to process the idle command.
*/
AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B); if (asc_dvc->chip_type == ADV_CHIP_ASC3550) { /* * Clear the tickle value. In the ASC-3550 the RISC flag * command 'clr_tickle_b' does not work unless the host * value is cleared.
*/
AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
}
/* Wait for up to 100 millisecond for the idle command to timeout. */ for (i = 0; i < SCSI_WAIT_100_MSEC; i++) { /* Poll once each microsecond for command completion. */ for (j = 0; j < SCSI_US_PER_MSEC; j++) {
AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS,
result); if (result != 0) return result;
udelay(1);
}
}
BUG(); /* The idle command should never timeout. */ return ADV_ERROR;
}
/* * Reset SCSI Bus and purge all outstanding requests. * * Return Value: * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset. * ADV_FALSE(0) - Microcode command failed. * ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC * may be hung which requires driver recovery.
*/ staticint AdvResetSB(ADV_DVC_VAR *asc_dvc)
{ int status;
/* * Send the SCSI Bus Reset idle start idle command which asserts * the SCSI Bus Reset signal.
*/
status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L); if (status != ADV_TRUE) { return status;
}
/* * Delay for the specified SCSI Bus Reset hold time. * * The hold time delay is done on the host because the RISC has no * microsecond accurate timer.
*/
udelay(ASC_SCSI_RESET_HOLD_TIME_US);
/* * Send the SCSI Bus Reset end idle command which de-asserts * the SCSI Bus Reset signal and purges any pending requests.
*/
status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L); if (status != ADV_TRUE) { return status;
}
/* * Initialize the ASC-3550. * * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. * * For a non-fatal error return a warning code. If there are no warnings * then 0 is returned. * * Needed after initialization for error recovery.
*/ staticint AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
{ conststruct firmware *fw; constchar fwname[] = "advansys/3550.bin";
AdvPortAddr iop_base;
ushort warn_code; int begin_addr; int end_addr;
ushort code_sum; int word; int i; int err; unsignedlong chksum;
ushort scsi_cfg1;
uchar tid;
ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
ushort wdtr_able = 0, sdtr_able, tagqng_able;
uchar max_cmd[ADV_MAX_TID + 1];
/* If there is already an error, don't continue. */ if (asc_dvc->err_code != 0) return ADV_ERROR;
/* * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
*/ if (asc_dvc->chip_type != ADV_CHIP_ASC3550) {
asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE; return ADV_ERROR;
}
warn_code = 0;
iop_base = asc_dvc->iop_base;
/* * Save the RISC memory BIOS region before writing the microcode. * The BIOS may already be loaded and using its RISC LRAM region * so its region must be saved and restored. * * Note: This code makes the assumption, which is currently true, * that a chip reset does not clear RISC LRAM.
*/ for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
bios_mem[i]);
}
/* * Save current per TID negotiated values.
*/ if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) {
ushort bios_version, major, minor;
bios_version =
bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2];
major = (bios_version >> 12) & 0xF;
minor = (bios_version >> 8) & 0xF; if (major < 3 || (major == 3 && minor == 1)) { /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
AdvReadWordLram(iop_base, 0x120, wdtr_able);
} else {
AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
}
}
AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); for (tid = 0; tid <= ADV_MAX_TID; tid++) {
AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
max_cmd[tid]);
}
/* * Restore the RISC memory BIOS region.
*/ for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
bios_mem[i]);
}
/* * Calculate and write the microcode code checksum to the microcode * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
*/
AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
code_sum = 0;
AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr); for (word = begin_addr; word < end_addr; word += 2) {
code_sum += AdvReadWordAutoIncLram(iop_base);
}
AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
/* * Read and save microcode version and date.
*/
AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
asc_dvc->cfg->mcode_date);
AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
asc_dvc->cfg->mcode_version);
/* * Set the chip type to indicate the ASC3550.
*/
AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
/* * If the PCI Configuration Command Register "Parity Error Response * Control" Bit was clear (0), then set the microcode variable * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode * to ignore DMA parity errors.
*/ if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
word |= CONTROL_FLAG_IGNORE_PERR;
AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
}
/* * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO * threshold of 128 bytes. This register is only accessible to the host.
*/
AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
START_CTL_EMFU | READ_CMD_MRM);
/* * Microcode operating variables for WDTR, SDTR, and command tag * queuing will be set in sdev_configure() based on what a * device reports it is capable of in Inquiry byte 7. * * If SCSI Bus Resets have been disabled, then directly set * SDTR and WDTR from the EEPROM configuration. This will allow * the BIOS and warm boot to work without a SCSI bus hang on * the Inquiry caused by host and target mismatched DTR values. * Without the SCSI Bus Reset, before an Inquiry a device can't * be assumed to be in Asynchronous, Narrow mode.
*/ if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
asc_dvc->wdtr_able);
AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
asc_dvc->sdtr_able);
}
/* * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2, * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID * bitmask. These values determine the maximum SDTR speed negotiated * with a device. * * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2, * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them * without determining here whether the device supports SDTR. * * 4-bit speed SDTR speed name * =========== =============== * 0000b (0x0) SDTR disabled * 0001b (0x1) 5 Mhz * 0010b (0x2) 10 Mhz * 0011b (0x3) 20 Mhz (Ultra) * 0100b (0x4) 40 Mhz (LVD/Ultra2) * 0101b (0x5) 80 Mhz (LVD2/Ultra3) * 0110b (0x6) Undefined * . * 1111b (0xF) Undefined
*/
word = 0; for (tid = 0; tid <= ADV_MAX_TID; tid++) { if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) { /* Set Ultra speed for TID 'tid'. */
word |= (0x3 << (4 * (tid % 4)));
} else { /* Set Fast speed for TID 'tid'. */
word |= (0x2 << (4 * (tid % 4)));
} if (tid == 3) { /* Check if done with sdtr_speed1. */
AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
word = 0;
} elseif (tid == 7) { /* Check if done with sdtr_speed2. */
AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
word = 0;
} elseif (tid == 11) { /* Check if done with sdtr_speed3. */
AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
word = 0;
} elseif (tid == 15) { /* Check if done with sdtr_speed4. */
AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word); /* End of loop. */
}
}
/* * Set microcode operating variable for the disconnect per TID bitmask.
*/
AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
asc_dvc->cfg->disc_enable);
/* * Set SCSI_CFG0 Microcode Default Value. * * The microcode will set the SCSI_CFG0 register using this value * after it is started below.
*/
AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
asc_dvc->chip_scsi_id);
/* * Determine SCSI_CFG1 Microcode Default Value. * * The microcode will set the SCSI_CFG1 register using this value * after it is started below.
*/
/* * If all three connectors are in use, return an error.
*/ if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
(scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION; return ADV_ERROR;
}
/* * If the internal narrow cable is reversed all of the SCSI_CTRL * register signals will be set. Check for and return an error if * this condition is found.
*/ if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE; return ADV_ERROR;
}
/* * If this is a differential board and a single-ended device * is attached to one of the connectors, return an error.
*/ if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) {
asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE; return ADV_ERROR;
}
/* * If automatic termination control is enabled, then set the * termination value based on a table listed in a_condor.h. * * If manual termination was specified with an EEPROM setting * then 'termination' was set-up in AdvInitFrom3550EEPROM() and * is ready to be 'ored' into SCSI_CFG1.
*/ if (asc_dvc->cfg->termination == 0) { /* * The software always controls termination by setting TERM_CTL_SEL. * If TERM_CTL_SEL were set to 0, the hardware would set termination.
*/
asc_dvc->cfg->termination |= TERM_CTL_SEL;
switch (scsi_cfg1 & CABLE_DETECT) { /* TERM_CTL_H: on, TERM_CTL_L: on */ case 0x3: case 0x7: case 0xB: case 0xD: case 0xE: case 0xF:
asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L); break;
/* TERM_CTL_H: on, TERM_CTL_L: off */ case 0x1: case 0x5: case 0x9: case 0xA: case 0xC:
asc_dvc->cfg->termination |= TERM_CTL_H; break;
/* TERM_CTL_H: off, TERM_CTL_L: off */ case 0x2: case 0x6: break;
}
}
/* * Clear any set TERM_CTL_H and TERM_CTL_L bits.
*/
scsi_cfg1 &= ~TERM_CTL;
/* * Invert the TERM_CTL_H and TERM_CTL_L bits and then * set 'scsi_cfg1'. The TERM_POL bit does not need to be * referenced, because the hardware internally inverts * the Termination High and Low bits if TERM_POL is set.
*/
scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
/* * Set SCSI_CFG1 Microcode Default Value * * Set filter value and possibly modified termination control * bits in the Microcode SCSI_CFG1 Register Value. * * The microcode will set the SCSI_CFG1 register using this value * after it is started below.
*/
AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
FLTR_DISABLE | scsi_cfg1);
/* * Set MEM_CFG Microcode Default Value * * The microcode will set the MEM_CFG register using this value * after it is started below. * * MEM_CFG may be accessed as a word or byte, but only bits 0-7 * are defined. * * ASC-3550 has 8KB internal memory.
*/
AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
BIOS_EN | RAM_SZ_8KB);
/* * Set SEL_MASK Microcode Default Value * * The microcode will set the SEL_MASK register using this value * after it is started below.
*/
AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
AdvBuildCarrierFreelist(asc_dvc);
/* * Set-up the Host->RISC Initiator Command Queue (ICQ).
*/
/* * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus * Resets should be performed. The RISC has to be running * to issue a SCSI Bus Reset.
*/ if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) { /* * If the BIOS Signature is present in memory, restore the * BIOS Handshake Configuration Table and do not perform * a SCSI Bus Reset.
*/ if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
0x55AA) { /* * Restore per TID negotiated values.
*/
AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
tagqng_able); for (tid = 0; tid <= ADV_MAX_TID; tid++) {
AdvWriteByteLram(iop_base,
ASC_MC_NUMBER_OF_MAX_CMD + tid,
max_cmd[tid]);
}
} else { if (AdvResetSB(asc_dvc) != ADV_TRUE) {
warn_code = ASC_WARN_BUSRESET_ERROR;
}
}
}
return warn_code;
}
/* * Initialize the ASC-38C0800. * * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. * * For a non-fatal error return a warning code. If there are no warnings * then 0 is returned. * * Needed after initialization for error recovery.
*/ staticint AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
{ conststruct firmware *fw; constchar fwname[] = "advansys/38C0800.bin";
AdvPortAddr iop_base;
ushort warn_code; int begin_addr; int end_addr;
ushort code_sum; int word; int i; int err; unsignedlong chksum;
ushort scsi_cfg1;
uchar byte;
uchar tid;
ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
ushort wdtr_able, sdtr_able, tagqng_able;
uchar max_cmd[ADV_MAX_TID + 1];
/* If there is already an error, don't continue. */ if (asc_dvc->err_code != 0) return ADV_ERROR;
/* * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
*/ if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) {
asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE; return ADV_ERROR;
}
warn_code = 0;
iop_base = asc_dvc->iop_base;
/* * Save the RISC memory BIOS region before writing the microcode. * The BIOS may already be loaded and using its RISC LRAM region * so its region must be saved and restored. * * Note: This code makes the assumption, which is currently true, * that a chip reset does not clear RISC LRAM.
*/ for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
bios_mem[i]);
}
/* * Save current per TID negotiated values.
*/
AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); for (tid = 0; tid <= ADV_MAX_TID; tid++) {
AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
max_cmd[tid]);
}
/* * RAM BIST (RAM Built-In Self Test) * * Address : I/O base + offset 0x38h register (byte). * Function: Bit 7-6(RW) : RAM mode * Normal Mode : 0x00 * Pre-test Mode : 0x40 * RAM Test Mode : 0x80 * Bit 5 : unused * Bit 4(RO) : Done bit * Bit 3-0(RO) : Status * Host Error : 0x08 * Int_RAM Error : 0x04 * RISC Error : 0x02 * SCSI Error : 0x01 * No Error : 0x00 * * Note: RAM BIST code should be put right here, before loading the * microcode and after saving the RISC memory BIOS region.
*/
/* * LRAM Pre-test * * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds. * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset * to NORMAL_MODE, return an error too.
*/ for (i = 0; i < 2; i++) {
AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
mdelay(10); /* Wait for 10ms before reading back. */
byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST); if ((byte & RAM_TEST_DONE) == 0
|| (byte & 0x0F) != PRE_TEST_VALUE) {
asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST; return ADV_ERROR;
}
AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
mdelay(10); /* Wait for 10ms before reading back. */ if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
!= NORMAL_VALUE) {
asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST; return ADV_ERROR;
}
}
/* * LRAM Test - It takes about 1.5 ms to run through the test. * * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds. * If Done bit not set or Status not 0, save register byte, set the * err_code, and return an error.
*/
AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
mdelay(10); /* Wait for 10ms before checking status. */
byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST); if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) { /* Get here if Done bit not set or Status not 0. */
asc_dvc->bist_err_code = byte; /* for BIOS display message */
asc_dvc->err_code = ASC_IERR_BIST_RAM_TEST; return ADV_ERROR;
}
/* We need to reset back to normal mode after LRAM test passes. */
AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
/* * Restore the RISC memory BIOS region.
*/ for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
bios_mem[i]);
}
/* * Calculate and write the microcode code checksum to the microcode * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
*/
AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
code_sum = 0;
AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr); for (word = begin_addr; word < end_addr; word += 2) {
code_sum += AdvReadWordAutoIncLram(iop_base);
}
AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
/* * Read microcode version and date.
*/
AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
asc_dvc->cfg->mcode_date);
AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
asc_dvc->cfg->mcode_version);
/* * Set the chip type to indicate the ASC38C0800.
*/
AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
/* * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register. * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current * cable detection and then we are able to read C_DET[3:0]. * * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1 * Microcode Default Value' section below.
*/
scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
scsi_cfg1 | DIS_TERM_DRV);
/* * If the PCI Configuration Command Register "Parity Error Response * Control" Bit was clear (0), then set the microcode variable * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode * to ignore DMA parity errors.
*/ if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
word |= CONTROL_FLAG_IGNORE_PERR;
AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
}
/* * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2] * bits for the default FIFO threshold. * * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes. * * For DMA Errata #4 set the BC_THRESH_ENB bit.
*/
AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH |
READ_CMD_MRM);
/* * Microcode operating variables for WDTR, SDTR, and command tag * queuing will be set in sdev_configure() based on what a * device reports it is capable of in Inquiry byte 7. * * If SCSI Bus Resets have been disabled, then directly set * SDTR and WDTR from the EEPROM configuration. This will allow * the BIOS and warm boot to work without a SCSI bus hang on * the Inquiry caused by host and target mismatched DTR values. * Without the SCSI Bus Reset, before an Inquiry a device can't * be assumed to be in Asynchronous, Narrow mode.
*/ if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
asc_dvc->wdtr_able);
AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
asc_dvc->sdtr_able);
}
/* * Set microcode operating variables for DISC and SDTR_SPEED1, * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM * configuration values. * * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2, * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them * without determining here whether the device supports SDTR.
*/
AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
asc_dvc->cfg->disc_enable);
AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
/* * Set SCSI_CFG0 Microcode Default Value. * * The microcode will set the SCSI_CFG0 register using this value * after it is started below.
*/
AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
asc_dvc->chip_scsi_id);
/* * Determine SCSI_CFG1 Microcode Default Value. * * The microcode will set the SCSI_CFG1 register using this value * after it is started below.
*/
/* * If the internal narrow cable is reversed all of the SCSI_CTRL * register signals will be set. Check for and return an error if * this condition is found.
*/ if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE; return ADV_ERROR;
}
/* * All kind of combinations of devices attached to one of four * connectors are acceptable except HVD device attached. For example, * LVD device can be attached to SE connector while SE device attached * to LVD connector. If LVD device attached to SE connector, it only * runs up to Ultra speed. * * If an HVD device is attached to one of LVD connectors, return an * error. However, there is no way to detect HVD device attached to * SE connectors.
*/ if (scsi_cfg1 & HVD) {
asc_dvc->err_code = ASC_IERR_HVD_DEVICE; return ADV_ERROR;
}
/* * If either SE or LVD automatic termination control is enabled, then * set the termination value based on a table listed in a_condor.h. * * If manual termination was specified with an EEPROM setting then * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready * to be 'ored' into SCSI_CFG1.
*/ if ((asc_dvc->cfg->termination & TERM_SE) == 0) { /* SE automatic termination control is enabled. */ switch (scsi_cfg1 & C_DET_SE) { /* TERM_SE_HI: on, TERM_SE_LO: on */ case 0x1: case 0x2: case 0x3:
asc_dvc->cfg->termination |= TERM_SE; break;
/* TERM_SE_HI: on, TERM_SE_LO: off */ case 0x0:
asc_dvc->cfg->termination |= TERM_SE_HI; break;
}
}
if ((asc_dvc->cfg->termination & TERM_LVD) == 0) { /* LVD automatic termination control is enabled. */ switch (scsi_cfg1 & C_DET_LVD) { /* TERM_LVD_HI: on, TERM_LVD_LO: on */ case 0x4: case 0x8: case 0xC:
asc_dvc->cfg->termination |= TERM_LVD; break;
/* TERM_LVD_HI: off, TERM_LVD_LO: off */ case 0x0: break;
}
}
/* * Clear any set TERM_SE and TERM_LVD bits.
*/
scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
/* * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
*/
scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
/* * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE * bits and set possibly modified termination control bits in the * Microcode SCSI_CFG1 Register Value.
*/
scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
/* * Set SCSI_CFG1 Microcode Default Value * * Set possibly modified termination control and reset DIS_TERM_DRV * bits in the Microcode SCSI_CFG1 Register Value. * * The microcode will set the SCSI_CFG1 register using this value * after it is started below.
*/
AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
/* * Set MEM_CFG Microcode Default Value * * The microcode will set the MEM_CFG register using this value * after it is started below. * * MEM_CFG may be accessed as a word or byte, but only bits 0-7 * are defined. * * ASC-38C0800 has 16KB internal memory.
*/
AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
BIOS_EN | RAM_SZ_16KB);
/* * Set SEL_MASK Microcode Default Value * * The microcode will set the SEL_MASK register using this value * after it is started below.
*/
AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
AdvBuildCarrierFreelist(asc_dvc);
/* * Set-up the Host->RISC Initiator Command Queue (ICQ).
*/
asc_dvc->icq_sp = adv_get_next_carrier(asc_dvc); if (!asc_dvc->icq_sp) {
ASC_DBG(0, "Failed to get ICQ carrier\n");
asc_dvc->err_code |= ASC_IERR_NO_CARRIER; return ADV_ERROR;
}
/* * Set RISC ICQ physical address start value. * carr_pa is LE, must be native before write
*/
AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
/* * Set-up the RISC->Host Initiator Response Queue (IRQ).
*/
asc_dvc->irq_sp = adv_get_next_carrier(asc_dvc); if (!asc_dvc->irq_sp) {
ASC_DBG(0, "Failed to get IRQ carrier\n");
asc_dvc->err_code |= ASC_IERR_NO_CARRIER; return ADV_ERROR;
}
/* * Set RISC IRQ physical address start value. * * carr_pa is LE, must be native before write *
*/
AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
asc_dvc->carr_pending_cnt = 0;
/* * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus * Resets should be performed. The RISC has to be running * to issue a SCSI Bus Reset.
*/ if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) { /* * If the BIOS Signature is present in memory, restore the * BIOS Handshake Configuration Table and do not perform * a SCSI Bus Reset.
*/ if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
0x55AA) { /* * Restore per TID negotiated values.
*/
AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
tagqng_able); for (tid = 0; tid <= ADV_MAX_TID; tid++) {
AdvWriteByteLram(iop_base,
ASC_MC_NUMBER_OF_MAX_CMD + tid,
max_cmd[tid]);
}
} else { if (AdvResetSB(asc_dvc) != ADV_TRUE) {
warn_code = ASC_WARN_BUSRESET_ERROR;
}
}
}
return warn_code;
}
/* * Initialize the ASC-38C1600. * * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR. * * For a non-fatal error return a warning code. If there are no warnings * then 0 is returned. * * Needed after initialization for error recovery.
*/ staticint AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
{ conststruct firmware *fw; constchar fwname[] = "advansys/38C1600.bin";
AdvPortAddr iop_base;
ushort warn_code; int begin_addr; int end_addr;
ushort code_sum; long word; int i; int err; unsignedlong chksum;
ushort scsi_cfg1;
uchar byte;
uchar tid;
ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
ushort wdtr_able, sdtr_able, ppr_able, tagqng_able;
uchar max_cmd[ASC_MAX_TID + 1];
/* If there is already an error, don't continue. */ if (asc_dvc->err_code != 0) { return ADV_ERROR;
}
/* * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
*/ if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE; return ADV_ERROR;
}
warn_code = 0;
iop_base = asc_dvc->iop_base;
/* * Save the RISC memory BIOS region before writing the microcode. * The BIOS may already be loaded and using its RISC LRAM region * so its region must be saved and restored. * * Note: This code makes the assumption, which is currently true, * that a chip reset does not clear RISC LRAM.
*/ for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
bios_mem[i]);
}
/* * Save current per TID negotiated values.
*/
AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); for (tid = 0; tid <= ASC_MAX_TID; tid++) {
AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
max_cmd[tid]);
}
/* * RAM BIST (Built-In Self Test) * * Address : I/O base + offset 0x38h register (byte). * Function: Bit 7-6(RW) : RAM mode * Normal Mode : 0x00 * Pre-test Mode : 0x40 * RAM Test Mode : 0x80 * Bit 5 : unused * Bit 4(RO) : Done bit * Bit 3-0(RO) : Status * Host Error : 0x08 * Int_RAM Error : 0x04 * RISC Error : 0x02 * SCSI Error : 0x01 * No Error : 0x00 * * Note: RAM BIST code should be put right here, before loading the * microcode and after saving the RISC memory BIOS region.
*/
/* * LRAM Pre-test * * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds. * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset * to NORMAL_MODE, return an error too.
*/ for (i = 0; i < 2; i++) {
AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
mdelay(10); /* Wait for 10ms before reading back. */
byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST); if ((byte & RAM_TEST_DONE) == 0
|| (byte & 0x0F) != PRE_TEST_VALUE) {
asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST; return ADV_ERROR;
}
AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
mdelay(10); /* Wait for 10ms before reading back. */ if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
!= NORMAL_VALUE) {
asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST; return ADV_ERROR;
}
}
/* * LRAM Test - It takes about 1.5 ms to run through the test. * * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds. * If Done bit not set or Status not 0, save register byte, set the * err_code, and return an error.
*/
AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
mdelay(10); /* Wait for 10ms before checking status. */
byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST); if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) { /* Get here if Done bit not set or Status not 0. */
asc_dvc->bist_err_code = byte; /* for BIOS display message */
asc_dvc->err_code = ASC_IERR_BIST_RAM_TEST; return ADV_ERROR;
}
/* We need to reset back to normal mode after LRAM test passes. */
AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
/* * Restore the RISC memory BIOS region.
*/ for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
bios_mem[i]);
}
/* * Calculate and write the microcode code checksum to the microcode * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
*/
AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
code_sum = 0;
AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr); for (word = begin_addr; word < end_addr; word += 2) {
code_sum += AdvReadWordAutoIncLram(iop_base);
}
AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
/* * Read microcode version and date.
*/
AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
asc_dvc->cfg->mcode_date);
AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
asc_dvc->cfg->mcode_version);
/* * Set the chip type to indicate the ASC38C1600.
*/
AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
/* * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register. * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current * cable detection and then we are able to read C_DET[3:0]. * * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1 * Microcode Default Value' section below.
*/
scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
scsi_cfg1 | DIS_TERM_DRV);
/* * If the PCI Configuration Command Register "Parity Error Response * Control" Bit was clear (0), then set the microcode variable * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode * to ignore DMA parity errors.
*/ if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
word |= CONTROL_FLAG_IGNORE_PERR;
AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
}
/* * If the BIOS control flag AIPP (Asynchronous Information * Phase Protection) disable bit is not set, then set the firmware * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable * AIPP checking and encoding.
*/ if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
word |= CONTROL_FLAG_ENABLE_AIPP;
AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
}
/* * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4], * and START_CTL_TH [3:2].
*/
AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
/* * Microcode operating variables for WDTR, SDTR, and command tag * queuing will be set in sdev_configure() based on what a * device reports it is capable of in Inquiry byte 7. * * If SCSI Bus Resets have been disabled, then directly set * SDTR and WDTR from the EEPROM configuration. This will allow * the BIOS and warm boot to work without a SCSI bus hang on * the Inquiry caused by host and target mismatched DTR values. * Without the SCSI Bus Reset, before an Inquiry a device can't * be assumed to be in Asynchronous, Narrow mode.
*/ if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
asc_dvc->wdtr_able);
AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
asc_dvc->sdtr_able);
}
/* * Set microcode operating variables for DISC and SDTR_SPEED1, * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM * configuration values. * * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2, * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them * without determining here whether the device supports SDTR.
*/
AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
asc_dvc->cfg->disc_enable);
AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
/* * Set SCSI_CFG0 Microcode Default Value. * * The microcode will set the SCSI_CFG0 register using this value * after it is started below.
*/
AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
asc_dvc->chip_scsi_id);
/* * Calculate SCSI_CFG1 Microcode Default Value. * * The microcode will set the SCSI_CFG1 register using this value * after it is started below. * * Each ASC-38C1600 function has only two cable detect bits. * The bus mode override bits are in IOPB_SOFT_OVER_WR.
*/
scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
/* * If the cable is reversed all of the SCSI_CTRL register signals * will be set. Check for and return an error if this condition is * found.
*/ if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE; return ADV_ERROR;
}
/* * Each ASC-38C1600 function has two connectors. Only an HVD device * can not be connected to either connector. An LVD device or SE device * may be connected to either connecor. If an SE device is connected, * then at most Ultra speed (20 Mhz) can be used on both connectors. * * If an HVD device is attached, return an error.
*/ if (scsi_cfg1 & HVD) {
asc_dvc->err_code |= ASC_IERR_HVD_DEVICE; return ADV_ERROR;
}
/* * Each function in the ASC-38C1600 uses only the SE cable detect and * termination because there are two connectors for each function. Each * function may use either LVD or SE mode. Corresponding the SE automatic * termination control EEPROM bits are used for each function. Each * function has its own EEPROM. If SE automatic control is enabled for * the function, then set the termination value based on a table listed * in a_condor.h. * * If manual termination is specified in the EEPROM for the function, * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is * ready to be 'ored' into SCSI_CFG1.
*/ if ((asc_dvc->cfg->termination & TERM_SE) == 0) { struct pci_dev *pdev = adv_dvc_to_pdev(asc_dvc); /* SE automatic termination control is enabled. */ switch (scsi_cfg1 & C_DET_SE) { /* TERM_SE_HI: on, TERM_SE_LO: on */ case 0x1: case 0x2: case 0x3:
asc_dvc->cfg->termination |= TERM_SE; break;
case 0x0: if (PCI_FUNC(pdev->devfn) == 0) { /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
} else { /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
asc_dvc->cfg->termination |= TERM_SE_HI;
} break;
}
}
/* * Clear any set TERM_SE bits.
*/
scsi_cfg1 &= ~TERM_SE;
/* * Invert the TERM_SE bits and then set 'scsi_cfg1'.
*/
scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
/* * Clear Big Endian and Terminator Polarity bits and set possibly * modified termination control bits in the Microcode SCSI_CFG1 * Register Value. * * Big Endian bit is not used even on big endian machines.
*/
scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
/* * Set SCSI_CFG1 Microcode Default Value * * Set possibly modified termination control bits in the Microcode * SCSI_CFG1 Register Value. * * The microcode will set the SCSI_CFG1 register using this value * after it is started below.
*/
AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
/* * Set MEM_CFG Microcode Default Value * * The microcode will set the MEM_CFG register using this value * after it is started below. * * MEM_CFG may be accessed as a word or byte, but only bits 0-7 * are defined. * * ASC-38C1600 has 32KB internal memory. * * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come * out a special 16K Adv Library and Microcode version. After the issue * resolved, we should turn back to the 32K support. Both a_condor.h and * mcode.sas files also need to be updated. * * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, * BIOS_EN | RAM_SZ_32KB);
*/
AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
BIOS_EN | RAM_SZ_16KB);
/* * Set SEL_MASK Microcode Default Value * * The microcode will set the SEL_MASK register using this value * after it is started below.
*/
AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
/* * Set RISC ICQ physical address start value. Initialize the * COMMA register to the same value otherwise the RISC will * prematurely detect a command is available.
*/
AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
le32_to_cpu(asc_dvc->icq_sp->carr_pa));
/* * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus * Resets should be performed. The RISC has to be running * to issue a SCSI Bus Reset.
*/ if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) { /* * If the BIOS Signature is present in memory, restore the * per TID microcode operating variables.
*/ if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
0x55AA) { /* * Restore per TID negotiated values.
*/
AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
tagqng_able); for (tid = 0; tid <= ASC_MAX_TID; tid++) {
AdvWriteByteLram(iop_base,
ASC_MC_NUMBER_OF_MAX_CMD + tid,
max_cmd[tid]);
}
} else { if (AdvResetSB(asc_dvc) != ADV_TRUE) {
warn_code = ASC_WARN_BUSRESET_ERROR;
}
}
}
return warn_code;
}
/* * Reset chip and SCSI Bus. * * Return Value: * ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful. * ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure.
*/ staticint AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
{ int status;
ushort wdtr_able, sdtr_able, tagqng_able;
ushort ppr_able = 0;
uchar tid, max_cmd[ADV_MAX_TID + 1];
AdvPortAddr iop_base;
ushort bios_sig;
iop_base = asc_dvc->iop_base;
/* * Save current per TID negotiated values.
*/
AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
}
AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); for (tid = 0; tid <= ADV_MAX_TID; tid++) {
AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
max_cmd[tid]);
}
/* * Force the AdvInitAsc3550/38C0800Driver() function to * perform a SCSI Bus Reset by clearing the BIOS signature word. * The initialization functions assumes a SCSI Bus Reset is not * needed if the BIOS signature word is present.
*/
AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
/* * Stop chip and reset it.
*/
AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
mdelay(100);
AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
ADV_CTRL_REG_CMD_WR_IO_REG);
/* * Reset Adv Library error code, if any, and try * re-initializing the chip.
*/
asc_dvc->err_code = 0; if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
status = AdvInitAsc38C1600Driver(asc_dvc);
} elseif (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
status = AdvInitAsc38C0800Driver(asc_dvc);
} else {
status = AdvInitAsc3550Driver(asc_dvc);
}
/* Translate initialization return value to status value. */ if (status == 0) {
status = ADV_TRUE;
} else {
status = ADV_FALSE;
}
/* * Restore the BIOS signature word.
*/
AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
/* * Restore per TID negotiated values.
*/
AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
}
AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); for (tid = 0; tid <= ADV_MAX_TID; tid++) {
AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
max_cmd[tid]);
}
return status;
}
/* * adv_async_callback() - Adv Library asynchronous event callback function.
*/ staticvoid adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
{ switch (code) { case ADV_ASYNC_SCSI_BUS_RESET_DET: /* * The firmware detected a SCSI Bus reset.
*/
ASC_DBG(0, "ADV_ASYNC_SCSI_BUS_RESET_DET\n"); break;
case ADV_ASYNC_RDMA_FAILURE: /* * Handle RDMA failure by resetting the SCSI Bus and * possibly the chip if it is unresponsive. Log the error * with a unique code.
*/
ASC_DBG(0, "ADV_ASYNC_RDMA_FAILURE\n");
AdvResetChipAndSB(adv_dvc_varp); break;
case ADV_HOST_SCSI_BUS_RESET: /* * Host generated SCSI bus reset occurred.
*/
ASC_DBG(0, "ADV_HOST_SCSI_BUS_RESET\n"); break;
/* * Get the adv_req_t structure for the command that has been * completed. The adv_req_t structure actually contains the * completed ADV_SCSI_REQ_Q structure.
*/
scp = scsi_host_find_tag(boardp->shost, scsiqp->srb_tag);
/* * 'done_status' contains the command's ending status.
*/
scp->result = 0; switch (scsiqp->done_status) { case QD_NO_ERROR:
ASC_DBG(2, "QD_NO_ERROR\n");
/* * Check for an underrun condition. * * If there was no error and an underrun condition, then * then return the number of underrun bytes.
*/
resid_cnt = le32_to_cpu(scsiqp->data_cnt); if (scsi_bufflen(scp) != 0 && resid_cnt != 0 &&
resid_cnt <= scsi_bufflen(scp)) {
ASC_DBG(1, "underrun condition %lu bytes\n",
(ulong)resid_cnt);
scsi_set_resid(scp, resid_cnt);
} break;
case QD_WITH_ERROR:
ASC_DBG(2, "QD_WITH_ERROR\n"); switch (scsiqp->host_status) { case QHSTA_NO_ERROR:
set_status_byte(scp, scsiqp->scsi_status); if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n");
ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
SCSI_SENSE_BUFFERSIZE);
} break;
default: /* Some other QHSTA error occurred. */
ASC_DBG(1, "host_status 0x%x\n", scsiqp->host_status);
set_host_byte(scp, DID_BAD_TARGET); break;
} break;
case QD_ABORTED_BY_HOST:
ASC_DBG(1, "QD_ABORTED_BY_HOST\n");
set_status_byte(scp, scsiqp->scsi_status);
set_host_byte(scp, DID_ABORT); break;
/* * If the 'init_tidmask' bit isn't already set for the target and the * current request finished normally, then set the bit for the target * to indicate that a device is present.
*/ if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
scsiqp->done_status == QD_NO_ERROR &&
scsiqp->host_status == QHSTA_NO_ERROR) {
boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
}
asc_scsi_done(scp);
/* * Free all 'adv_sgblk_t' structures allocated for the request.
*/ while ((sgblkp = reqp->sgblkp) != NULL) { /* Remove 'sgblkp' from the request list. */
reqp->sgblkp = sgblkp->next_sgblkp;
/* * Adv Library Interrupt Service Routine * * This function is called by a driver's interrupt service routine. * The function disables and re-enables interrupts. * * When a microcode idle command is completed, the ADV_DVC_VAR * 'idle_cmd_done' field is set to ADV_TRUE. * * Note: AdvISR() can be called when interrupts are disabled or even * when there is no hardware interrupt condition present. It will * always check for completed idle commands and microcode requests. * This is an important feature that shouldn't be changed because it * allows commands to be completed from polling mode loops. * * Return: * ADV_TRUE(1) - interrupt was pending * ADV_FALSE(0) - no interrupt was pending
*/ staticint AdvISR(ADV_DVC_VAR *asc_dvc)
{
AdvPortAddr iop_base;
uchar int_stat;
ADV_CARR_T *free_carrp;
__le32 irq_next_vpa;
ADV_SCSI_REQ_Q *scsiq;
adv_req_t *reqp;
iop_base = asc_dvc->iop_base;
/* Reading the register clears the interrupt. */
int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
/* * Notify the driver of an asynchronous microcode condition by * calling the adv_async_callback function. The function * is passed the microcode ASC_MC_INTRB_CODE byte value.
*/ if (int_stat & ADV_INTR_STATUS_INTRB) {
uchar intrb_code;
/* * Check if the IRQ stopper carrier contains a completed request.
*/ while (((irq_next_vpa =
le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ADV_RQ_DONE) != 0) { /* * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure. * The RISC will have set 'areq_vpa' to a virtual address. * * The firmware will have copied the ADV_SCSI_REQ_Q.scsiq_ptr * field to the carrier ADV_CARR_T.areq_vpa field. The conversion * below complements the conversion of ADV_SCSI_REQ_Q.scsiq_ptr' * in AdvExeScsiQueue().
*/
u32 pa_offset = le32_to_cpu(asc_dvc->irq_sp->areq_vpa);
ASC_DBG(1, "irq_sp %p areq_vpa %u\n",
asc_dvc->irq_sp, pa_offset);
reqp = adv_get_reqp(asc_dvc, pa_offset);
scsiq = &reqp->scsi_req_q;
/* * Request finished with good status and the queue was not * DMAed to host memory by the firmware. Set all status fields * to indicate good status.
*/ if ((irq_next_vpa & ADV_RQ_GOOD) != 0) {
scsiq->done_status = QD_NO_ERROR;
scsiq->host_status = scsiq->scsi_status = 0;
scsiq->data_cnt = 0L;
}
/* * Advance the stopper pointer to the next carrier * ignoring the lower four bits. Free the previous * stopper carrier.
*/
free_carrp = asc_dvc->irq_sp;
asc_dvc->irq_sp = adv_get_carrier(asc_dvc,
ADV_GET_CARRP(irq_next_vpa));
/* * Notify the driver of the completed request by passing * the ADV_SCSI_REQ_Q pointer to its callback function.
*/
adv_isr_callback(asc_dvc, scsiq); /* * Note: After the driver callback function is called, 'scsiq' * can no longer be referenced. * * Fall through and continue processing other completed * requests...
*/
} return ADV_TRUE;
}
/* * Set the device queue depth to the * number of active requests when the * QUEUE FULL condition was encountered.
*/
boardp->queue_full |= target_id;
boardp->queue_full_cnt[tid_no] =
cur_dvc_qng;
}
}
}
AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); return;
} return;
}
/* * void * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words) * * Calling/Exit State: * none * * Description: * Input an ASC_QDONE_INFO structure from the chip
*/ staticvoid
DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
{ int i;
ushort word;
AscSetChipLramAddr(iop_base, s_addr); for (i = 0; i < 2 * words; i += 2) { if (i == 10) { continue;
}
word = inpw(iop_base + IOP_RAM_DATA);
inbuf[i] = word & 0xff;
inbuf[i + 1] = (word >> 8) & 0xff;
}
ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
}
/* * Read high word of remain bytes from alternate location.
*/
scsiq->remain_bytes = (((u32)AscReadLramWord(iop_base,
(ushort)(q_addr +
(ushort)
ASC_SCSIQ_W_ALT_DC1)))
<< 16); /* * Read low word of remain bytes from original location.
*/
scsiq->remain_bytes += AscReadLramWord(iop_base,
(ushort)(q_addr + (ushort)
ASC_SCSIQ_DW_REMAIN_XFER_CNT));
/* * Decrease the srb_tag by 1 to find the SCSI command
*/
srb_tag = qdonep->d2.srb_tag - 1;
scp = scsi_host_find_tag(boardp->shost, srb_tag); if (!scp) return;
/* * Check for an underrun condition. * * If there was no error and an underrun condition, then * return the number of underrun bytes.
*/ if (scsi_bufflen(scp) != 0 && qdonep->remain_bytes != 0 &&
qdonep->remain_bytes <= scsi_bufflen(scp)) {
ASC_DBG(1, "underrun condition %u bytes\n",
(unsigned)qdonep->remain_bytes);
scsi_set_resid(scp, qdonep->remain_bytes);
} break;
case QD_WITH_ERROR:
ASC_DBG(2, "QD_WITH_ERROR\n"); switch (qdonep->d3.host_stat) { case QHSTA_NO_ERROR:
set_status_byte(scp, qdonep->d3.scsi_stat); if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n");
ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
SCSI_SENSE_BUFFERSIZE);
} break;
/* * If the 'init_tidmask' bit isn't already set for the target and the * current request finished normally, then set the bit for the target * to indicate that a device is present.
*/ if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
qdonep->d3.done_stat == QD_NO_ERROR &&
qdonep->d3.host_stat == QHSTA_NO_ERROR) {
boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
}
/* * advansys_reset() * * Reset the host associated with the command 'scp'. * * This function runs its own thread. Interrupts must be blocked but * sleeping is allowed and no locking other than for host structures is * required. Returns SUCCESS or FAILED.
*/ staticint advansys_reset(struct scsi_cmnd *scp)
{ struct Scsi_Host *shost = scp->device->host; struct asc_board *boardp = shost_priv(shost); unsignedlong flags; int status; int ret = SUCCESS;
if (ASC_NARROW_BOARD(boardp)) {
ASC_DVC_VAR *asc_dvc = &boardp->dvc_var.asc_dvc_var;
/* Reset the chip and SCSI bus. */
ASC_DBG(1, "before AscInitAsc1000Driver()\n");
status = AscInitAsc1000Driver(asc_dvc);
/* Refer to ASC_IERR_* definitions for meaning of 'err_code'. */ if (asc_dvc->err_code || !asc_dvc->overrun_dma) {
scmd_printk(KERN_INFO, scp, "SCSI host reset error: " "0x%x, status: 0x%x\n", asc_dvc->err_code,
status);
ret = FAILED;
} elseif (status) {
scmd_printk(KERN_INFO, scp, "SCSI host reset warning: " "0x%x\n", status);
} else {
scmd_printk(KERN_INFO, scp, "SCSI host reset " "successful\n");
}
ASC_DBG(1, "after AscInitAsc1000Driver()\n");
} else { /* * If the suggest reset bus flags are set, then reset the bus. * Otherwise only reset the device.
*/
ADV_DVC_VAR *adv_dvc = &boardp->dvc_var.adv_dvc_var;
/* * Reset the chip and SCSI bus.
*/
ASC_DBG(1, "before AdvResetChipAndSB()\n"); switch (AdvResetChipAndSB(adv_dvc)) { case ASC_TRUE:
scmd_printk(KERN_INFO, scp, "SCSI host reset " "successful\n"); break; case ASC_FALSE: default:
scmd_printk(KERN_INFO, scp, "SCSI host reset error\n");
ret = FAILED; break;
}
spin_lock_irqsave(shost->host_lock, flags);
AdvISR(adv_dvc);
spin_unlock_irqrestore(shost->host_lock, flags);
}
ASC_DBG(1, "ret %d\n", ret);
return ret;
}
/* * advansys_biosparam() * * Translate disk drive geometry if the "BIOS greater than 1 GB" * support is enabled for a drive. * * ip (information pointer) is an int array with the following definition: * ip[0]: heads * ip[1]: sectors * ip[2]: cylinders
*/ staticint
advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
sector_t capacity, int ip[])
{ struct asc_board *boardp = shost_priv(sdev->host);
/* * Wide Transfers * * If the EEPROM enabled WDTR for the device and the device supports wide * bus (16 bit) transfers, then turn on the device's 'wdtr_able' bit and * write the new value to the microcode.
*/ staticvoid
advansys_wide_enable_wdtr(AdvPortAddr iop_base, unsignedshort tidmask)
{ unsignedshort cfg_word;
AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word); if ((cfg_word & tidmask) != 0) return;
/* * Clear the microcode SDTR and WDTR negotiation done indicators for * the target to cause it to negotiate with the new setting set above. * WDTR when accepted causes the target to enter asynchronous mode, so * SDTR must be negotiated.
*/
AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
cfg_word &= ~tidmask;
AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
cfg_word &= ~tidmask;
AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
}
/* * Synchronous Transfers * * If the EEPROM enabled SDTR for the device and the device * supports synchronous transfers, then turn on the device's * 'sdtr_able' bit. Write the new value to the microcode.
*/ staticvoid
advansys_wide_enable_sdtr(AdvPortAddr iop_base, unsignedshort tidmask)
{ unsignedshort cfg_word;
AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word); if ((cfg_word & tidmask) != 0) return;
/* * Clear the microcode "SDTR negotiation" done indicator for the * target to cause it to negotiate with the new setting set above.
*/
AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
cfg_word &= ~tidmask;
AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
}
/* * PPR (Parallel Protocol Request) Capable * * If the device supports DT mode, then it must be PPR capable. * The PPR message will be used in place of the SDTR and WDTR * messages to negotiate synchronous speed and offset, transfer * width, and protocol options.
*/ staticvoid advansys_wide_enable_ppr(ADV_DVC_VAR *adv_dvc,
AdvPortAddr iop_base, unsignedshort tidmask)
{
AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
adv_dvc->ppr_able |= tidmask;
AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
}
if (sdev->lun == 0) { /* * Handle WDTR, SDTR, and Tag Queuing. If the feature * is enabled in the EEPROM and the device supports the * feature, then enable it in the microcode.
*/
if ((adv_dvc->wdtr_able & tidmask) && sdev->wdtr)
advansys_wide_enable_wdtr(iop_base, tidmask); if ((adv_dvc->sdtr_able & tidmask) && sdev->sdtr)
advansys_wide_enable_sdtr(iop_base, tidmask); if (adv_dvc->chip_type == ADV_CHIP_ASC38C1600 && sdev->ppr)
advansys_wide_enable_ppr(adv_dvc, iop_base, tidmask);
/* * Tag Queuing is disabled for the BIOS which runs in polled * mode and would see no benefit from Tag Queuing. Also by * disabling Tag Queuing in the BIOS devices with Tag Queuing * bugs will at least work with the BIOS.
*/ if ((adv_dvc->tagqng_able & tidmask) &&
sdev->tagged_supported) { unsignedshort cfg_word;
AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
cfg_word |= tidmask;
AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
cfg_word);
AdvWriteByteLram(iop_base,
ASC_MC_NUMBER_OF_MAX_CMD + sdev->id,
adv_dvc->max_dvc_qng);
}
}
if ((adv_dvc->tagqng_able & tidmask) && sdev->tagged_supported)
scsi_change_queue_depth(sdev, adv_dvc->max_dvc_qng);
}
/* * Set the number of commands to queue per device for the * specified host adapter.
*/ staticint advansys_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim)
{ struct asc_board *boardp = shost_priv(sdev->host);
if (ASC_NARROW_BOARD(boardp))
advansys_narrow_sdev_configure(sdev,
&boardp->dvc_var.asc_dvc_var); else
advansys_wide_sdev_configure(sdev,
&boardp->dvc_var.adv_dvc_var);
/* * Set the srb_tag to the command tag + 1, as * srb_tag '0' is used internally by the chip.
*/
srb_tag = scsi_cmd_to_rq(scp)->tag + 1;
asc_scsi_q->q2.srb_tag = srb_tag;
/* * If there are any outstanding requests for the current target, * then every 255th request send an ORDERED request. This heuristic * tries to retain the benefit of request sorting while preventing * request starvation. 255 is the max number of tags or pending commands * a device may have outstanding. * * The request count is incremented below for every successfully * started request. *
*/ if ((asc_dvc->cur_dvc_qng[scp->device->id] > 0) &&
(boardp->reqcnt[scp->device->id] % 255) == 0) {
asc_scsi_q->q2.tag_code = ORDERED_QUEUE_TAG;
} else {
asc_scsi_q->q2.tag_code = SIMPLE_QUEUE_TAG;
}
asc_scsi_q->q1.cntl |= QC_SG_HEAD;
asc_scsi_q->sg_head = asc_sg_head;
asc_scsi_q->q1.data_cnt = 0;
asc_scsi_q->q1.data_addr = 0; /* This is a byte value, otherwise it would need to be swapped. */
asc_sg_head->entry_cnt = asc_scsi_q->q1.sg_queue_cnt = use_sg;
ASC_STATS_ADD(scp->device->host, xfer_elem,
asc_sg_head->entry_cnt);
/* * Build scatter-gather list for Adv Library (Wide Board). * * Additional ADV_SG_BLOCK structures will need to be allocated * if the total number of scatter-gather elements exceeds * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are * assumed to be physically contiguous. * * Return: * ADV_SUCCESS(1) - SG List successfully created * ADV_ERROR(-1) - SG List creation failed
*/ staticint
adv_get_sglist(struct asc_board *boardp, adv_req_t *reqp,
ADV_SCSI_REQ_Q *scsiqp, struct scsi_cmnd *scp, int use_sg)
{
adv_sgblk_t *sgblkp, *prev_sgblkp; struct scatterlist *slp; int sg_elem_cnt;
ADV_SG_BLOCK *sg_block, *prev_sg_block;
dma_addr_t sgblk_paddr; int i;
/* * Check if this is the first 'adv_sgblk_t' for the * request.
*/ if (reqp->sgblkp == NULL) { /* Request's first scatter-gather block. */
reqp->sgblkp = sgblkp;
/* * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical * address pointers.
*/
scsiqp->sg_list_ptr = sg_block;
scsiqp->sg_real_addr = cpu_to_le32(sgblk_paddr);
} else { /* Request's second or later scatter-gather block. */
prev_sgblkp->next_sgblkp = sgblkp;
/* * Point the previous ADV_SG_BLOCK structure to * the newly allocated ADV_SG_BLOCK structure.
*/
prev_sg_block->sg_ptr = cpu_to_le32(sgblk_paddr);
}
for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
sg_block->sg_list[i].sg_addr =
cpu_to_le32(sg_dma_address(slp));
sg_block->sg_list[i].sg_count =
cpu_to_le32(sg_dma_len(slp));
ASC_STATS_ADD(scp->device->host, xfer_sect,
DIV_ROUND_UP(sg_dma_len(slp), 512));
if (--sg_elem_cnt == 0) { /* * Last ADV_SG_BLOCK and scatter-gather entry.
*/
sg_block->sg_cnt = i + 1;
sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */ return ADV_SUCCESS;
}
slp = sg_next(slp);
}
sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
prev_sg_block = sg_block;
prev_sgblkp = sgblkp;
}
}
/* * Build a request structure for the Adv Library (Wide Board). * * If an adv_req_t can not be allocated to issue the request, * then return ASC_BUSY. If an error occurs, then return ASC_ERROR. * * Multi-byte fields in the ADV_SCSI_REQ_Q that are used by the * microcode for DMA addresses or math operations are byte swapped * to little-endian order.
*/ staticint
adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
adv_req_t **adv_reqpp)
{
u32 srb_tag = scsi_cmd_to_rq(scp)->tag;
adv_req_t *reqp;
ADV_SCSI_REQ_Q *scsiqp; int ret; int use_sg;
dma_addr_t sense_addr;
/* * Allocate an adv_req_t structure from the board to execute * the command.
*/
reqp = &boardp->adv_reqp[srb_tag]; if (reqp->cmndp && reqp->cmndp != scp ) {
ASC_DBG(1, "no free adv_req_t\n");
ASC_STATS(scp->device->host, adv_build_noreq); return ASC_BUSY;
}
/* * Set the srb_tag to the command tag.
*/
scsiqp->srb_tag = srb_tag;
/* * Set 'host_scribble' to point to the adv_req_t structure.
*/
reqp->cmndp = scp;
scp->host_scribble = (void *)reqp;
/* * Build the ADV_SCSI_REQ_Q request.
*/
/* Set CDB length and copy it to the request structure. */
scsiqp->cdb_len = scp->cmd_len; /* Copy first 12 CDB bytes to cdb[]. */
memcpy(scsiqp->cdb, scp->cmnd, scp->cmd_len < 12 ? scp->cmd_len : 12); /* Copy last 4 CDB bytes, if present, to cdb16[]. */ if (scp->cmd_len > 12) { int cdb16_len = scp->cmd_len - 12;
iop_base = asc_dvc->iop_base;
sg_head = scsiq->sg_head;
saved_data_addr = scsiq->q1.data_addr;
saved_data_cnt = scsiq->q1.data_cnt;
scsiq->q1.data_addr = cpu_to_le32(sg_head->sg_list[0].addr);
scsiq->q1.data_cnt = cpu_to_le32(sg_head->sg_list[0].bytes); /* * Set sg_entry_cnt to be the number of SG elements that * will fit in the allocated SG queues. It is minus 1, because * the first SG element is handled above.
*/
sg_entry_cnt = sg_head->entry_cnt - 1;
/* * AdvExeScsiQueue() - Send a request to the RISC microcode program. * * Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q, * add the carrier to the ICQ (Initiator Command Queue), and tickle the * RISC to notify it a new command is ready to be executed. * * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be * set to SCSI_MAX_RETRY. * * Multi-byte fields in the ADV_SCSI_REQ_Q that are used by the microcode * for DMA addresses or math operations are byte swapped to little-endian * order. * * Return: * ADV_SUCCESS(1) - The request was successfully queued. * ADV_BUSY(0) - Resource unavailable; Retry again after pending * request completes. * ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure * host IC error.
*/ staticint AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, adv_req_t *reqp)
{
AdvPortAddr iop_base;
ADV_CARR_T *new_carrp;
ADV_SCSI_REQ_Q *scsiq = &reqp->scsi_req_q;
/* * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
*/ if (scsiq->target_id > ADV_MAX_TID) {
scsiq->host_status = QHSTA_M_INVALID_DEVICE;
scsiq->done_status = QD_WITH_ERROR; return ADV_ERROR;
}
iop_base = asc_dvc->iop_base;
/* * Allocate a carrier ensuring at least one carrier always * remains on the freelist and initialize fields.
*/
new_carrp = adv_get_next_carrier(asc_dvc); if (!new_carrp) {
ASC_DBG(1, "No free carriers\n"); return ADV_BUSY;
}
asc_dvc->carr_pending_cnt++;
/* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
scsiq->scsiq_ptr = cpu_to_le32(scsiq->srb_tag);
scsiq->scsiq_rptr = cpu_to_le32(reqp->req_addr);
/* * Use the current stopper to send the ADV_SCSI_REQ_Q command to * the microcode. The newly allocated stopper will become the new * stopper.
*/
asc_dvc->icq_sp->areq_vpa = scsiq->scsiq_rptr;
/* * Set the 'next_vpa' pointer for the old stopper to be the * physical address of the new stopper. The RISC can only * follow physical addresses.
*/
asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
/* * Set the host adapter stopper pointer to point to the new carrier.
*/
asc_dvc->icq_sp = new_carrp;
if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
asc_dvc->chip_type == ADV_CHIP_ASC38C0800) { /* * Tickle the RISC to tell it to read its Command Queue Head pointer.
*/
AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A); if (asc_dvc->chip_type == ADV_CHIP_ASC3550) { /* * Clear the tickle value. In the ASC-3550 the RISC flag * command 'clr_tickle_a' does not work unless the host * value is cleared.
*/
AdvWriteByteRegister(iop_base, IOPB_TICKLE,
ADV_TICKLE_NOP);
}
} elseif (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) { /* * Notify the RISC a carrier is ready by writing the physical * address of the new carrier stopper to the COMMA register.
*/
AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
le32_to_cpu(new_carrp->carr_pa));
}
return ADV_SUCCESS;
}
/* * Execute a single 'struct scsi_cmnd'.
*/ staticint asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
{ int ret, err_code; struct asc_board *boardp = shost_priv(scp->device->host);
ASC_DBG(1, "scp 0x%p\n", scp);
if (ASC_NARROW_BOARD(boardp)) {
ASC_DVC_VAR *asc_dvc = &boardp->dvc_var.asc_dvc_var; struct asc_scsi_q asc_scsi_q;
ret = asc_build_req(boardp, scp, &asc_scsi_q); if (ret != ASC_NOERROR) {
ASC_STATS(scp->device->host, build_error); return ret;
}
/* * advansys_queuecommand() - interrupt-driven I/O entrypoint. * * This function always returns 0. Command return status is saved * in the 'scp' result field.
*/ staticint advansys_queuecommand_lck(struct scsi_cmnd *scp)
{ struct Scsi_Host *shost = scp->device->host; int asc_res, result = 0;
ASC_STATS(shost, queuecommand);
asc_res = asc_execute_scsi_cmnd(scp);
switch (asc_res) { case ASC_NOERROR: break; case ASC_BUSY:
result = SCSI_MLQUEUE_HOST_BUSY; break; case ASC_ERROR: default:
asc_scsi_done(scp); break;
}
/* * Return the BIOS address of the adapter at the specified * I/O port and with the specified bus type.
*/ staticunsignedshort AscGetChipBiosAddress(PortAddr iop_base, unsignedshort bus_type)
{ unsignedshort cfg_lsw; unsignedshort bios_addr;
/* * The PCI BIOS is re-located by the motherboard BIOS. Because * of this the driver can not determine where a PCI BIOS is * loaded and executes.
*/ if (bus_type & ASC_IS_PCI) return 0;
switch (warn_code) { case 0: /* No error. */ break; case ASC_WARN_IO_PORT_ROTATE:
shost_printk(KERN_WARNING, shost, "I/O port address " "modified\n"); break; case ASC_WARN_AUTO_CONFIG:
shost_printk(KERN_WARNING, shost, "I/O port increment switch " "enabled\n"); break; case ASC_WARN_EEPROM_CHKSUM:
shost_printk(KERN_WARNING, shost, "EEPROM checksum error\n"); break; case ASC_WARN_IRQ_MODIFIED:
shost_printk(KERN_WARNING, shost, "IRQ modified\n"); break; case ASC_WARN_CMD_QNG_CONFLICT:
shost_printk(KERN_WARNING, shost, "tag queuing w/o " "disconnects\n"); break; default:
shost_printk(KERN_WARNING, shost, "unknown warning: 0x%x\n",
warn_code); break;
}
if (asc_dvc->err_code != 0)
shost_printk(KERN_ERR, shost, "error 0x%x at init_state " "0x%x\n", asc_dvc->err_code, asc_dvc->init_state);
return asc_dvc->err_code;
}
/* * EEPROM Configuration. * * All drivers should use this structure to set the default EEPROM * configuration. The BIOS now uses this structure when it is built. * Additional structure information can be found in a_condor.h where * the structure is defined. * * The *_Field_IsChar structs are needed to correct for endianness. * These values are read from the board 16 bits at a time directly * into the structs. Because some fields are char, the values will be * in the wrong order. The *_Field_IsChar tells when to flip the * bytes. Data read and written to PCI memory is automatically swapped * on big-endian platforms so char fields read as words are actually being * unswapped on big-endian platforms.
*/ #ifdef CONFIG_PCI static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config = {
ADV_EEPROM_BIOS_ENABLE, /* cfg_lsw */
0x0000, /* cfg_msw */
0xFFFF, /* disc_enable */
0xFFFF, /* wdtr_able */
0xFFFF, /* sdtr_able */
0xFFFF, /* start_motor */
0xFFFF, /* tagqng_able */
0xFFFF, /* bios_scan */
0, /* scam_tolerant */
7, /* adapter_scsi_id */
0, /* bios_boot_delay */
3, /* scsi_reset_delay */
0, /* bios_id_lun */
0, /* termination */
0, /* reserved1 */
0xFFE7, /* bios_ctrl */
0xFFFF, /* ultra_able */
0, /* reserved2 */
ASC_DEF_MAX_HOST_QNG, /* max_host_qng */
ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
0, /* dvc_cntl */
0, /* bug_fix */
0, /* serial_number_word1 */
0, /* serial_number_word2 */
0, /* serial_number_word3 */
0, /* check_sum */
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
, /* oem_name[16] */
0, /* dvc_err_code */
0, /* adv_err_code */
0, /* adv_err_addr */
0, /* saved_dvc_err_code */
0, /* saved_adv_err_code */
0, /* saved_adv_err_addr */
0 /* num_of_err */
};
for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
wval = AdvReadEEPWord(iop_base, eep_addr);
chksum += wval; /* Checksum is calculated from word values. */ if (*charfields++) {
*wbuf = le16_to_cpu(wval);
} else {
*wbuf = wval;
}
} /* Read checksum word. */
*wbuf = AdvReadEEPWord(iop_base, eep_addr);
wbuf++;
charfields++;
/* Read rest of EEPROM not covered by the checksum. */ for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
*wbuf = AdvReadEEPWord(iop_base, eep_addr); if (*charfields++) {
*wbuf = le16_to_cpu(*wbuf);
}
} return chksum;
}
/* * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while * all of this is done. * * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. * * For a non-fatal error return a warning code. If there are no warnings * then 0 is returned. * * Note: Chip is stopped on entry.
*/ staticint AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
{
AdvPortAddr iop_base;
ushort warn_code;
ADVEEP_3550_CONFIG eep_config;
iop_base = asc_dvc->iop_base;
warn_code = 0;
/* * Read the board's EEPROM configuration. * * Set default values if a bad checksum is found.
*/ if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum) {
warn_code |= ASC_WARN_EEPROM_CHKSUM;
/* * Set EEPROM default values.
*/
memcpy(&eep_config, &Default_3550_EEPROM_Config, sizeof(ADVEEP_3550_CONFIG));
/* * Assume the 6 byte board serial number that was read from * EEPROM is correct even if the EEPROM checksum failed.
*/
eep_config.serial_number_word3 =
AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
AdvSet3550EEPConfig(iop_base, &eep_config);
} /* * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the * EEPROM configuration that was read. * * This is the mapping of EEPROM fields to Adv Library fields.
*/
asc_dvc->wdtr_able = eep_config.wdtr_able;
asc_dvc->sdtr_able = eep_config.sdtr_able;
asc_dvc->ultra_able = eep_config.ultra_able;
asc_dvc->tagqng_able = eep_config.tagqng_able;
asc_dvc->cfg->disc_enable = eep_config.disc_enable;
asc_dvc->max_host_qng = eep_config.max_host_qng;
asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
asc_dvc->start_motor = eep_config.start_motor;
asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
asc_dvc->bios_ctrl = eep_config.bios_ctrl;
asc_dvc->no_scam = eep_config.scam_tolerant;
asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
/* * Set the host maximum queuing (max. 253, min. 16) and the per device * maximum queuing (max. 63, min. 4).
*/ if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
} elseif (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) { /* If the value is zero, assume it is uninitialized. */ if (eep_config.max_host_qng == 0) {
eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
} else {
eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
}
}
if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
} elseif (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) { /* If the value is zero, assume it is uninitialized. */ if (eep_config.max_dvc_qng == 0) {
eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
} else {
eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
}
}
/* * If 'max_dvc_qng' is greater than 'max_host_qng', then * set 'max_dvc_qng' to 'max_host_qng'.
*/ if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
eep_config.max_dvc_qng = eep_config.max_host_qng;
}
/* * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng' * values based on possibly adjusted EEPROM values.
*/
asc_dvc->max_host_qng = eep_config.max_host_qng;
asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
/* * If the EEPROM 'termination' field is set to automatic (0), then set * the ADV_DVC_CFG 'termination' field to automatic also. * * If the termination is specified with a non-zero 'termination' * value check that a legal value is set and set the ADV_DVC_CFG * 'termination' field appropriately.
*/ if (eep_config.termination == 0) {
asc_dvc->cfg->termination = 0; /* auto termination */
} else { /* Enable manual control with low off / high off. */ if (eep_config.termination == 1) {
asc_dvc->cfg->termination = TERM_CTL_SEL;
/* Enable manual control with low off / high on. */
} elseif (eep_config.termination == 2) {
asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
/* Enable manual control with low on / high on. */
} elseif (eep_config.termination == 3) {
asc_dvc->cfg->termination =
TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
} else { /* * The EEPROM 'termination' field contains a bad value. Use * automatic termination instead.
*/
asc_dvc->cfg->termination = 0;
warn_code |= ASC_WARN_EEPROM_TERMINATION;
}
}
return warn_code;
}
/* * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while * all of this is done. * * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. * * For a non-fatal error return a warning code. If there are no warnings * then 0 is returned. * * Note: Chip is stopped on entry.
*/ staticint AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
{
AdvPortAddr iop_base;
ushort warn_code;
ADVEEP_38C0800_CONFIG eep_config;
uchar tid, termination;
ushort sdtr_speed = 0;
iop_base = asc_dvc->iop_base;
warn_code = 0;
/* * Read the board's EEPROM configuration. * * Set default values if a bad checksum is found.
*/ if (AdvGet38C0800EEPConfig(iop_base, &eep_config) !=
eep_config.check_sum) {
warn_code |= ASC_WARN_EEPROM_CHKSUM;
/* * Set EEPROM default values.
*/
memcpy(&eep_config, &Default_38C0800_EEPROM_Config, sizeof(ADVEEP_38C0800_CONFIG));
/* * Assume the 6 byte board serial number that was read from * EEPROM is correct even if the EEPROM checksum failed.
*/
eep_config.serial_number_word3 =
AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
AdvSet38C0800EEPConfig(iop_base, &eep_config);
} /* * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the * EEPROM configuration that was read. * * This is the mapping of EEPROM fields to Adv Library fields.
*/
asc_dvc->wdtr_able = eep_config.wdtr_able;
asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
asc_dvc->tagqng_able = eep_config.tagqng_able;
asc_dvc->cfg->disc_enable = eep_config.disc_enable;
asc_dvc->max_host_qng = eep_config.max_host_qng;
asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
asc_dvc->start_motor = eep_config.start_motor;
asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
asc_dvc->bios_ctrl = eep_config.bios_ctrl;
asc_dvc->no_scam = eep_config.scam_tolerant;
asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
/* * For every Target ID if any of its 'sdtr_speed[1234]' bits * are set, then set an 'sdtr_able' bit for it.
*/
asc_dvc->sdtr_able = 0; for (tid = 0; tid <= ADV_MAX_TID; tid++) { if (tid == 0) {
sdtr_speed = asc_dvc->sdtr_speed1;
} elseif (tid == 4) {
sdtr_speed = asc_dvc->sdtr_speed2;
} elseif (tid == 8) {
sdtr_speed = asc_dvc->sdtr_speed3;
} elseif (tid == 12) {
sdtr_speed = asc_dvc->sdtr_speed4;
} if (sdtr_speed & ADV_MAX_TID) {
asc_dvc->sdtr_able |= (1 << tid);
}
sdtr_speed >>= 4;
}
/* * Set the host maximum queuing (max. 253, min. 16) and the per device * maximum queuing (max. 63, min. 4).
*/ if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
} elseif (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) { /* If the value is zero, assume it is uninitialized. */ if (eep_config.max_host_qng == 0) {
eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
} else {
eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
}
}
if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
} elseif (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) { /* If the value is zero, assume it is uninitialized. */ if (eep_config.max_dvc_qng == 0) {
eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
} else {
eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
}
}
/* * If 'max_dvc_qng' is greater than 'max_host_qng', then * set 'max_dvc_qng' to 'max_host_qng'.
*/ if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
eep_config.max_dvc_qng = eep_config.max_host_qng;
}
/* * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng' * values based on possibly adjusted EEPROM values.
*/
asc_dvc->max_host_qng = eep_config.max_host_qng;
asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
/* * If the EEPROM 'termination' field is set to automatic (0), then set * the ADV_DVC_CFG 'termination' field to automatic also. * * If the termination is specified with a non-zero 'termination' * value check that a legal value is set and set the ADV_DVC_CFG * 'termination' field appropriately.
*/ if (eep_config.termination_se == 0) {
termination = 0; /* auto termination for SE */
} else { /* Enable manual control with low off / high off. */ if (eep_config.termination_se == 1) {
termination = 0;
/* Enable manual control with low off / high on. */
} elseif (eep_config.termination_se == 2) {
termination = TERM_SE_HI;
/* Enable manual control with low on / high on. */
} elseif (eep_config.termination_se == 3) {
termination = TERM_SE;
} else { /* * The EEPROM 'termination_se' field contains a bad value. * Use automatic termination instead.
*/
termination = 0;
warn_code |= ASC_WARN_EEPROM_TERMINATION;
}
}
if (eep_config.termination_lvd == 0) {
asc_dvc->cfg->termination = termination; /* auto termination for LVD */
} else { /* Enable manual control with low off / high off. */ if (eep_config.termination_lvd == 1) {
asc_dvc->cfg->termination = termination;
/* Enable manual control with low off / high on. */
} elseif (eep_config.termination_lvd == 2) {
asc_dvc->cfg->termination = termination | TERM_LVD_HI;
/* Enable manual control with low on / high on. */
} elseif (eep_config.termination_lvd == 3) {
asc_dvc->cfg->termination = termination | TERM_LVD;
} else { /* * The EEPROM 'termination_lvd' field contains a bad value. * Use automatic termination instead.
*/
asc_dvc->cfg->termination = termination;
warn_code |= ASC_WARN_EEPROM_TERMINATION;
}
}
return warn_code;
}
/* * Read the board's EEPROM configuration. Set fields in ASC_DVC_VAR and * ASC_DVC_CFG based on the EEPROM settings. The chip is stopped while * all of this is done. * * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR. * * For a non-fatal error return a warning code. If there are no warnings * then 0 is returned. * * Note: Chip is stopped on entry.
*/ staticint AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
{
AdvPortAddr iop_base;
ushort warn_code;
ADVEEP_38C1600_CONFIG eep_config;
uchar tid, termination;
ushort sdtr_speed = 0;
iop_base = asc_dvc->iop_base;
warn_code = 0;
/* * Read the board's EEPROM configuration. * * Set default values if a bad checksum is found.
*/ if (AdvGet38C1600EEPConfig(iop_base, &eep_config) !=
eep_config.check_sum) { struct pci_dev *pdev = adv_dvc_to_pdev(asc_dvc);
warn_code |= ASC_WARN_EEPROM_CHKSUM;
/* * Set EEPROM default values.
*/
memcpy(&eep_config, &Default_38C1600_EEPROM_Config, sizeof(ADVEEP_38C1600_CONFIG));
if (PCI_FUNC(pdev->devfn) != 0) {
u8 ints; /* * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60 * and old Mac system booting problem. The Expansion * ROM must be disabled in Function 1 for these systems
*/
eep_config.cfg_lsw &= ~ADV_EEPROM_BIOS_ENABLE; /* * Clear the INTAB (bit 11) if the GPIO 0 input * indicates the Function 1 interrupt line is wired * to INTB. * * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input: * 1 - Function 1 interrupt line wired to INT A. * 0 - Function 1 interrupt line wired to INT B. * * Note: Function 0 is always wired to INTA. * Put all 5 GPIO bits in input mode and then read * their input values.
*/
AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL, 0);
ints = AdvReadByteRegister(iop_base, IOPB_GPIO_DATA); if ((ints & 0x01) == 0)
eep_config.cfg_lsw &= ~ADV_EEPROM_INTAB;
}
/* * Assume the 6 byte board serial number that was read from * EEPROM is correct even if the EEPROM checksum failed.
*/
eep_config.serial_number_word3 =
AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
eep_config.serial_number_word2 =
AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
eep_config.serial_number_word1 =
AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
AdvSet38C1600EEPConfig(iop_base, &eep_config);
}
/* * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the * EEPROM configuration that was read. * * This is the mapping of EEPROM fields to Adv Library fields.
*/
asc_dvc->wdtr_able = eep_config.wdtr_able;
asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
asc_dvc->ppr_able = 0;
asc_dvc->tagqng_able = eep_config.tagqng_able;
asc_dvc->cfg->disc_enable = eep_config.disc_enable;
asc_dvc->max_host_qng = eep_config.max_host_qng;
asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID);
asc_dvc->start_motor = eep_config.start_motor;
asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
asc_dvc->bios_ctrl = eep_config.bios_ctrl;
asc_dvc->no_scam = eep_config.scam_tolerant;
/* * For every Target ID if any of its 'sdtr_speed[1234]' bits * are set, then set an 'sdtr_able' bit for it.
*/
asc_dvc->sdtr_able = 0; for (tid = 0; tid <= ASC_MAX_TID; tid++) { if (tid == 0) {
sdtr_speed = asc_dvc->sdtr_speed1;
} elseif (tid == 4) {
sdtr_speed = asc_dvc->sdtr_speed2;
} elseif (tid == 8) {
sdtr_speed = asc_dvc->sdtr_speed3;
} elseif (tid == 12) {
sdtr_speed = asc_dvc->sdtr_speed4;
} if (sdtr_speed & ASC_MAX_TID) {
asc_dvc->sdtr_able |= (1 << tid);
}
sdtr_speed >>= 4;
}
/* * Set the host maximum queuing (max. 253, min. 16) and the per device * maximum queuing (max. 63, min. 4).
*/ if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
} elseif (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) { /* If the value is zero, assume it is uninitialized. */ if (eep_config.max_host_qng == 0) {
eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
} else {
eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
}
}
if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
} elseif (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) { /* If the value is zero, assume it is uninitialized. */ if (eep_config.max_dvc_qng == 0) {
eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
} else {
eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
}
}
/* * If 'max_dvc_qng' is greater than 'max_host_qng', then * set 'max_dvc_qng' to 'max_host_qng'.
*/ if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
eep_config.max_dvc_qng = eep_config.max_host_qng;
}
/* * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng' * values based on possibly adjusted EEPROM values.
*/
asc_dvc->max_host_qng = eep_config.max_host_qng;
asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
/* * If the EEPROM 'termination' field is set to automatic (0), then set * the ASC_DVC_CFG 'termination' field to automatic also. * * If the termination is specified with a non-zero 'termination' * value check that a legal value is set and set the ASC_DVC_CFG * 'termination' field appropriately.
*/ if (eep_config.termination_se == 0) {
termination = 0; /* auto termination for SE */
} else { /* Enable manual control with low off / high off. */ if (eep_config.termination_se == 1) {
termination = 0;
/* Enable manual control with low off / high on. */
} elseif (eep_config.termination_se == 2) {
termination = TERM_SE_HI;
/* Enable manual control with low on / high on. */
} elseif (eep_config.termination_se == 3) {
termination = TERM_SE;
} else { /* * The EEPROM 'termination_se' field contains a bad value. * Use automatic termination instead.
*/
termination = 0;
warn_code |= ASC_WARN_EEPROM_TERMINATION;
}
}
if (eep_config.termination_lvd == 0) {
asc_dvc->cfg->termination = termination; /* auto termination for LVD */
} else { /* Enable manual control with low off / high off. */ if (eep_config.termination_lvd == 1) {
asc_dvc->cfg->termination = termination;
/* Enable manual control with low off / high on. */
} elseif (eep_config.termination_lvd == 2) {
asc_dvc->cfg->termination = termination | TERM_LVD_HI;
/* Enable manual control with low on / high on. */
} elseif (eep_config.termination_lvd == 3) {
asc_dvc->cfg->termination = termination | TERM_LVD;
} else { /* * The EEPROM 'termination_lvd' field contains a bad value. * Use automatic termination instead.
*/
asc_dvc->cfg->termination = termination;
warn_code |= ASC_WARN_EEPROM_TERMINATION;
}
}
return warn_code;
}
/* * Initialize the ADV_DVC_VAR structure. * * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. * * For a non-fatal error return a warning code. If there are no warnings * then 0 is returned.
*/ staticint AdvInitGetConfig(struct pci_dev *pdev, struct Scsi_Host *shost)
{ struct asc_board *board = shost_priv(shost);
ADV_DVC_VAR *asc_dvc = &board->dvc_var.adv_dvc_var; unsignedshort warn_code = 0;
AdvPortAddr iop_base = asc_dvc->iop_base;
u16 cmd; int status;
asc_dvc->err_code = 0;
/* * Save the state of the PCI Configuration Command Register * "Parity Error Response Control" Bit. If the bit is clear (0), * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore * DMA parity errors.
*/
asc_dvc->cfg->control_flag = 0;
pci_read_config_word(pdev, PCI_COMMAND, &cmd); if ((cmd & PCI_COMMAND_PARITY) == 0)
asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
/* * Allocate buffer carrier structures. The total size * is about 8 KB, so allocate all at once.
*/
adv_dvc->carrier = dma_alloc_coherent(board->dev,
ADV_CARRIER_BUFSIZE, &adv_dvc->carrier_addr, GFP_KERNEL);
ASC_DBG(1, "carrier 0x%p\n", adv_dvc->carrier);
if (!adv_dvc->carrier) goto kmalloc_failed;
/* * Allocate up to 'max_host_qng' request structures for the Wide * board. The total size is about 16 KB, so allocate all at once. * If the allocation fails decrement and try again.
*/
board->adv_reqp_size = adv_dvc->max_host_qng * sizeof(adv_req_t); if (board->adv_reqp_size & 0x1f) {
ASC_DBG(1, "unaligned reqp %lu bytes\n", sizeof(adv_req_t));
board->adv_reqp_size = ADV_32BALIGN(board->adv_reqp_size);
}
board->adv_reqp = dma_alloc_coherent(board->dev, board->adv_reqp_size,
&board->adv_reqp_addr, GFP_KERNEL);
/* * Allocate up to ADV_TOT_SG_BLOCK request structures for * the Wide board. Each structure is about 136 bytes.
*/
sgblk_pool_size = sizeof(adv_sgblk_t) * ADV_TOT_SG_BLOCK;
board->adv_sgblk_pool = dma_pool_create("adv_sgblk", board->dev,
sgblk_pool_size, 32, 0);
/* * Even though it isn't used to access wide boards, other * than for the debug line below, save I/O Port address so * that it can be reported.
*/
boardp->ioport = iop;
if (ASC_NARROW_BOARD(boardp)) { /* * Set the board bus type and PCI IRQ before * calling AscInitGetConfig().
*/ switch (asc_dvc_varp->bus_type) { #ifdef CONFIG_ISA case ASC_IS_VL:
share_irq = 0; break; case ASC_IS_EISA:
share_irq = IRQF_SHARED; break; #endif/* CONFIG_ISA */ #ifdef CONFIG_PCI case ASC_IS_PCI:
share_irq = IRQF_SHARED; break; #endif/* CONFIG_PCI */ default:
shost_printk(KERN_ERR, shost, "unknown adapter type: " "%d\n", asc_dvc_varp->bus_type);
share_irq = 0; break;
}
/* * NOTE: AscInitGetConfig() may change the board's * bus_type value. The bus_type value should no * longer be used. If the bus_type field must be * referenced only use the bit-wise AND operator "&".
*/
ASC_DBG(2, "AscInitGetConfig()\n");
ret = AscInitGetConfig(shost) ? -ENODEV : 0;
} else { #ifdef CONFIG_PCI /* * For Wide boards set PCI information before calling * AdvInitGetConfig().
*/
share_irq = IRQF_SHARED;
ASC_DBG(2, "AdvInitGetConfig()\n");
ret = AdvInitGetConfig(pdev, shost) ? -ENODEV : 0; #else
share_irq = 0;
ret = -ENODEV; #endif/* CONFIG_PCI */
}
if (ret) goto err_unmap;
/* * Save the EEPROM configuration so that it can be displayed * from /proc/scsi/advansys/[0...].
*/ if (ASC_NARROW_BOARD(boardp)) {
ASCEEP_CONFIG *ep;
/* * Set the adapter's target id bit in the 'init_tidmask' field.
*/
boardp->init_tidmask |=
ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id);
/* * Save EEPROM settings for the board.
*/
ep = &boardp->eep_config.asc_eep;
ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable;
ep->disc_enable = asc_dvc_varp->cfg->disc_enable;
ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
ASC_EEP_SET_DMA_SPD(ep, ASC_DEF_ISA_DMA_SPEED);
ep->start_motor = asc_dvc_varp->start_motor;
ep->cntl = asc_dvc_varp->dvc_cntl;
ep->no_scam = asc_dvc_varp->no_scam;
ep->max_total_qng = asc_dvc_varp->max_total_qng;
ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id); /* 'max_tag_qng' is set to the same value for every device. */
ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0];
ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1];
ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2];
ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];
/* * Set the adapter's target id bit in the 'init_tidmask' field.
*/
boardp->init_tidmask |=
ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
}
/* * Channels are numbered beginning with 0. For AdvanSys one host * structure supports one channel. Multi-channel boards have a * separate host structure for each channel.
*/
shost->max_channel = 0; if (ASC_NARROW_BOARD(boardp)) {
shost->max_id = ASC_MAX_TID + 1;
shost->max_lun = ASC_MAX_LUN + 1;
shost->max_cmd_len = ASC_MAX_CDB_LEN;
/* Set maximum number of queues the adapter can handle. */
shost->can_queue = asc_dvc_varp->max_total_qng;
} else {
shost->max_id = ADV_MAX_TID + 1;
shost->max_lun = ADV_MAX_LUN + 1;
shost->max_cmd_len = ADV_MAX_CDB_LEN;
/* * Save the I/O Port address and length even though * I/O ports are not used to access Wide boards. * Instead the Wide boards are accessed with * PCI Memory Mapped I/O.
*/
shost->io_port = iop;
shost->this_id = adv_dvc_varp->chip_scsi_id;
/* Set maximum number of queues the adapter can handle. */
shost->can_queue = adv_dvc_varp->max_host_qng;
}
/* * Set the maximum number of scatter-gather elements the * adapter can handle.
*/ if (ASC_NARROW_BOARD(boardp)) { /* * Allow two commands with 'sg_tablesize' scatter-gather * elements to be executed simultaneously. This value is * the theoretical hardware limit. It may be decreased * below.
*/
shost->sg_tablesize =
(((asc_dvc_varp->max_total_qng - 2) / 2) *
ASC_SG_LIST_PER_Q) + 1;
} else {
shost->sg_tablesize = ADV_MAX_SG_LIST;
}
/* * The value of 'sg_tablesize' can not exceed the SCSI * mid-level driver definition of SG_ALL. SG_ALL also * must not be exceeded, because it is used to define the * size of the scatter-gather table in 'struct asc_sg_head'.
*/ if (shost->sg_tablesize > SG_ALL) {
shost->sg_tablesize = SG_ALL;
}
/* * If the BIOS saved a valid signature, then fill in * the BIOS code segment base address.
*/ if (boardp->bios_signature == 0x55AA) { /* * Convert x86 realmode code segment to a linear * address by shifting left 4.
*/
shost->base = ((ulong)boardp->bios_codeseg << 4);
} else {
shost->base = 0;
}
}
if (!request_region(iop_base, ASC_IOADR_GAP, DRV_NAME)) {
ASC_DBG(1, "I/O port 0x%x busy\n", iop_base); return -ENODEV;
}
ASC_DBG(1, "probing I/O port 0x%x\n", iop_base); if (!AscFindSignature(iop_base)) goto release_region; /* * I don't think this condition can actually happen, but the old * driver did it, and the chances of finding a VLB setup in 2007 * to do testing with is slight to none.
*/ if (AscGetChipVersion(iop_base, ASC_IS_VL) > ASC_CHIP_MAX_VER_VL) goto release_region;
/* * EISA is a little more tricky than PCI; each EISA device may have two * channels, and this driver is written to make each channel its own Scsi_Host
*/ struct eisa_scsi_data { struct Scsi_Host *host[2];
};
/* * The EISA IRQ number is found in bits 8 to 10 of the CfgLsw. It decodes as: * 000: 10 * 001: 11 * 010: 12 * 011: invalid * 100: 14 * 101: 15 * 110: invalid * 111: invalid
*/ staticunsignedint advansys_eisa_irq_no(struct eisa_device *edev)
{ unsignedshort cfg_lsw = inw(edev->base_addr + 0xc86); unsignedint chip_irq = ((cfg_lsw >> 8) & 0x07) + 10; if ((chip_irq == 13) || (chip_irq > 15)) return 0; return chip_irq;
}
staticint advansys_eisa_probe(struct device *dev)
{ int i, ioport, irq = 0; int err; struct eisa_device *edev = to_eisa_device(dev); struct eisa_scsi_data *data;
err = -ENOMEM;
data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) goto fail;
ioport = edev->base_addr + 0xc30;
err = -ENODEV; for (i = 0; i < 2; i++, ioport += 0x20) { struct asc_board *board; struct Scsi_Host *shost; if (!request_region(ioport, ASC_IOADR_GAP, DRV_NAME)) {
printk(KERN_WARNING "Region %x-%x busy\n", ioport,
ioport + ASC_IOADR_GAP - 1); continue;
} if (!AscFindSignature(ioport)) {
release_region(ioport, ASC_IOADR_GAP); continue;
}
/* * I don't know why we need to do this for EISA chips, but * not for any others. It looks to be equivalent to * AscGetChipCfgMsw, but I may have overlooked something, * so I'm not converting it until I get an EISA board to * test with.
*/
inw(ioport + 4);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.