162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * SuperTrak EX Series Storage Controller driver for Linux 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2005-2015 Promise Technology Inc. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Written By: 862306a36Sopenharmony_ci * Ed Lin <promise_linux@promise.com> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/init.h> 1262306a36Sopenharmony_ci#include <linux/errno.h> 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/delay.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci#include <linux/time.h> 1762306a36Sopenharmony_ci#include <linux/pci.h> 1862306a36Sopenharmony_ci#include <linux/blkdev.h> 1962306a36Sopenharmony_ci#include <linux/interrupt.h> 2062306a36Sopenharmony_ci#include <linux/types.h> 2162306a36Sopenharmony_ci#include <linux/module.h> 2262306a36Sopenharmony_ci#include <linux/spinlock.h> 2362306a36Sopenharmony_ci#include <linux/ktime.h> 2462306a36Sopenharmony_ci#include <linux/reboot.h> 2562306a36Sopenharmony_ci#include <asm/io.h> 2662306a36Sopenharmony_ci#include <asm/irq.h> 2762306a36Sopenharmony_ci#include <asm/byteorder.h> 2862306a36Sopenharmony_ci#include <scsi/scsi.h> 2962306a36Sopenharmony_ci#include <scsi/scsi_device.h> 3062306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h> 3162306a36Sopenharmony_ci#include <scsi/scsi_host.h> 3262306a36Sopenharmony_ci#include <scsi/scsi_tcq.h> 3362306a36Sopenharmony_ci#include <scsi/scsi_dbg.h> 3462306a36Sopenharmony_ci#include <scsi/scsi_eh.h> 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define DRV_NAME "stex" 3762306a36Sopenharmony_ci#define ST_DRIVER_VERSION "6.02.0000.01" 3862306a36Sopenharmony_ci#define ST_VER_MAJOR 6 3962306a36Sopenharmony_ci#define ST_VER_MINOR 02 4062306a36Sopenharmony_ci#define ST_OEM 0000 4162306a36Sopenharmony_ci#define ST_BUILD_VER 01 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cienum { 4462306a36Sopenharmony_ci /* MU register offset */ 4562306a36Sopenharmony_ci IMR0 = 0x10, /* MU_INBOUND_MESSAGE_REG0 */ 4662306a36Sopenharmony_ci IMR1 = 0x14, /* MU_INBOUND_MESSAGE_REG1 */ 4762306a36Sopenharmony_ci OMR0 = 0x18, /* MU_OUTBOUND_MESSAGE_REG0 */ 4862306a36Sopenharmony_ci OMR1 = 0x1c, /* MU_OUTBOUND_MESSAGE_REG1 */ 4962306a36Sopenharmony_ci IDBL = 0x20, /* MU_INBOUND_DOORBELL */ 5062306a36Sopenharmony_ci IIS = 0x24, /* MU_INBOUND_INTERRUPT_STATUS */ 5162306a36Sopenharmony_ci IIM = 0x28, /* MU_INBOUND_INTERRUPT_MASK */ 5262306a36Sopenharmony_ci ODBL = 0x2c, /* MU_OUTBOUND_DOORBELL */ 5362306a36Sopenharmony_ci OIS = 0x30, /* MU_OUTBOUND_INTERRUPT_STATUS */ 5462306a36Sopenharmony_ci OIM = 0x3c, /* MU_OUTBOUND_INTERRUPT_MASK */ 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci YIOA_STATUS = 0x00, 5762306a36Sopenharmony_ci YH2I_INT = 0x20, 5862306a36Sopenharmony_ci YINT_EN = 0x34, 5962306a36Sopenharmony_ci YI2H_INT = 0x9c, 6062306a36Sopenharmony_ci YI2H_INT_C = 0xa0, 6162306a36Sopenharmony_ci YH2I_REQ = 0xc0, 6262306a36Sopenharmony_ci YH2I_REQ_HI = 0xc4, 6362306a36Sopenharmony_ci PSCRATCH0 = 0xb0, 6462306a36Sopenharmony_ci PSCRATCH1 = 0xb4, 6562306a36Sopenharmony_ci PSCRATCH2 = 0xb8, 6662306a36Sopenharmony_ci PSCRATCH3 = 0xbc, 6762306a36Sopenharmony_ci PSCRATCH4 = 0xc8, 6862306a36Sopenharmony_ci MAILBOX_BASE = 0x1000, 6962306a36Sopenharmony_ci MAILBOX_HNDSHK_STS = 0x0, 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci /* MU register value */ 7262306a36Sopenharmony_ci MU_INBOUND_DOORBELL_HANDSHAKE = (1 << 0), 7362306a36Sopenharmony_ci MU_INBOUND_DOORBELL_REQHEADCHANGED = (1 << 1), 7462306a36Sopenharmony_ci MU_INBOUND_DOORBELL_STATUSTAILCHANGED = (1 << 2), 7562306a36Sopenharmony_ci MU_INBOUND_DOORBELL_HMUSTOPPED = (1 << 3), 7662306a36Sopenharmony_ci MU_INBOUND_DOORBELL_RESET = (1 << 4), 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci MU_OUTBOUND_DOORBELL_HANDSHAKE = (1 << 0), 7962306a36Sopenharmony_ci MU_OUTBOUND_DOORBELL_REQUESTTAILCHANGED = (1 << 1), 8062306a36Sopenharmony_ci MU_OUTBOUND_DOORBELL_STATUSHEADCHANGED = (1 << 2), 8162306a36Sopenharmony_ci MU_OUTBOUND_DOORBELL_BUSCHANGE = (1 << 3), 8262306a36Sopenharmony_ci MU_OUTBOUND_DOORBELL_HASEVENT = (1 << 4), 8362306a36Sopenharmony_ci MU_OUTBOUND_DOORBELL_REQUEST_RESET = (1 << 27), 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* MU status code */ 8662306a36Sopenharmony_ci MU_STATE_STARTING = 1, 8762306a36Sopenharmony_ci MU_STATE_STARTED = 2, 8862306a36Sopenharmony_ci MU_STATE_RESETTING = 3, 8962306a36Sopenharmony_ci MU_STATE_FAILED = 4, 9062306a36Sopenharmony_ci MU_STATE_STOP = 5, 9162306a36Sopenharmony_ci MU_STATE_NOCONNECT = 6, 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci MU_MAX_DELAY = 50, 9462306a36Sopenharmony_ci MU_HANDSHAKE_SIGNATURE = 0x55aaaa55, 9562306a36Sopenharmony_ci MU_HANDSHAKE_SIGNATURE_HALF = 0x5a5a0000, 9662306a36Sopenharmony_ci MU_HARD_RESET_WAIT = 30000, 9762306a36Sopenharmony_ci HMU_PARTNER_TYPE = 2, 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /* firmware returned values */ 10062306a36Sopenharmony_ci SRB_STATUS_SUCCESS = 0x01, 10162306a36Sopenharmony_ci SRB_STATUS_ERROR = 0x04, 10262306a36Sopenharmony_ci SRB_STATUS_BUSY = 0x05, 10362306a36Sopenharmony_ci SRB_STATUS_INVALID_REQUEST = 0x06, 10462306a36Sopenharmony_ci SRB_STATUS_SELECTION_TIMEOUT = 0x0A, 10562306a36Sopenharmony_ci SRB_SEE_SENSE = 0x80, 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci /* task attribute */ 10862306a36Sopenharmony_ci TASK_ATTRIBUTE_SIMPLE = 0x0, 10962306a36Sopenharmony_ci TASK_ATTRIBUTE_HEADOFQUEUE = 0x1, 11062306a36Sopenharmony_ci TASK_ATTRIBUTE_ORDERED = 0x2, 11162306a36Sopenharmony_ci TASK_ATTRIBUTE_ACA = 0x4, 11262306a36Sopenharmony_ci}; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cienum { 11562306a36Sopenharmony_ci SS_STS_NORMAL = 0x80000000, 11662306a36Sopenharmony_ci SS_STS_DONE = 0x40000000, 11762306a36Sopenharmony_ci SS_STS_HANDSHAKE = 0x20000000, 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci SS_HEAD_HANDSHAKE = 0x80, 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci SS_H2I_INT_RESET = 0x100, 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci SS_I2H_REQUEST_RESET = 0x2000, 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci SS_MU_OPERATIONAL = 0x80000000, 12662306a36Sopenharmony_ci}; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cienum { 12962306a36Sopenharmony_ci STEX_CDB_LENGTH = 16, 13062306a36Sopenharmony_ci STATUS_VAR_LEN = 128, 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* sg flags */ 13362306a36Sopenharmony_ci SG_CF_EOT = 0x80, /* end of table */ 13462306a36Sopenharmony_ci SG_CF_64B = 0x40, /* 64 bit item */ 13562306a36Sopenharmony_ci SG_CF_HOST = 0x20, /* sg in host memory */ 13662306a36Sopenharmony_ci MSG_DATA_DIR_ND = 0, 13762306a36Sopenharmony_ci MSG_DATA_DIR_IN = 1, 13862306a36Sopenharmony_ci MSG_DATA_DIR_OUT = 2, 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci st_shasta = 0, 14162306a36Sopenharmony_ci st_vsc = 1, 14262306a36Sopenharmony_ci st_yosemite = 2, 14362306a36Sopenharmony_ci st_seq = 3, 14462306a36Sopenharmony_ci st_yel = 4, 14562306a36Sopenharmony_ci st_P3 = 5, 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci PASSTHRU_REQ_TYPE = 0x00000001, 14862306a36Sopenharmony_ci PASSTHRU_REQ_NO_WAKEUP = 0x00000100, 14962306a36Sopenharmony_ci ST_INTERNAL_TIMEOUT = 180, 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci ST_TO_CMD = 0, 15262306a36Sopenharmony_ci ST_FROM_CMD = 1, 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci /* vendor specific commands of Promise */ 15562306a36Sopenharmony_ci MGT_CMD = 0xd8, 15662306a36Sopenharmony_ci SINBAND_MGT_CMD = 0xd9, 15762306a36Sopenharmony_ci ARRAY_CMD = 0xe0, 15862306a36Sopenharmony_ci CONTROLLER_CMD = 0xe1, 15962306a36Sopenharmony_ci DEBUGGING_CMD = 0xe2, 16062306a36Sopenharmony_ci PASSTHRU_CMD = 0xe3, 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci PASSTHRU_GET_ADAPTER = 0x05, 16362306a36Sopenharmony_ci PASSTHRU_GET_DRVVER = 0x10, 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci CTLR_CONFIG_CMD = 0x03, 16662306a36Sopenharmony_ci CTLR_SHUTDOWN = 0x0d, 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci CTLR_POWER_STATE_CHANGE = 0x0e, 16962306a36Sopenharmony_ci CTLR_POWER_SAVING = 0x01, 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci PASSTHRU_SIGNATURE = 0x4e415041, 17262306a36Sopenharmony_ci MGT_CMD_SIGNATURE = 0xba, 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci INQUIRY_EVPD = 0x01, 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci ST_ADDITIONAL_MEM = 0x200000, 17762306a36Sopenharmony_ci ST_ADDITIONAL_MEM_MIN = 0x80000, 17862306a36Sopenharmony_ci PMIC_SHUTDOWN = 0x0D, 17962306a36Sopenharmony_ci PMIC_REUMSE = 0x10, 18062306a36Sopenharmony_ci ST_IGNORED = -1, 18162306a36Sopenharmony_ci ST_NOTHANDLED = 7, 18262306a36Sopenharmony_ci ST_S3 = 3, 18362306a36Sopenharmony_ci ST_S4 = 4, 18462306a36Sopenharmony_ci ST_S5 = 5, 18562306a36Sopenharmony_ci ST_S6 = 6, 18662306a36Sopenharmony_ci}; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistruct st_sgitem { 18962306a36Sopenharmony_ci u8 ctrl; /* SG_CF_xxx */ 19062306a36Sopenharmony_ci u8 reserved[3]; 19162306a36Sopenharmony_ci __le32 count; 19262306a36Sopenharmony_ci __le64 addr; 19362306a36Sopenharmony_ci}; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistruct st_ss_sgitem { 19662306a36Sopenharmony_ci __le32 addr; 19762306a36Sopenharmony_ci __le32 addr_hi; 19862306a36Sopenharmony_ci __le32 count; 19962306a36Sopenharmony_ci}; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistruct st_sgtable { 20262306a36Sopenharmony_ci __le16 sg_count; 20362306a36Sopenharmony_ci __le16 max_sg_count; 20462306a36Sopenharmony_ci __le32 sz_in_byte; 20562306a36Sopenharmony_ci}; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistruct st_msg_header { 20862306a36Sopenharmony_ci __le64 handle; 20962306a36Sopenharmony_ci u8 flag; 21062306a36Sopenharmony_ci u8 channel; 21162306a36Sopenharmony_ci __le16 timeout; 21262306a36Sopenharmony_ci u32 reserved; 21362306a36Sopenharmony_ci}; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistruct handshake_frame { 21662306a36Sopenharmony_ci __le64 rb_phy; /* request payload queue physical address */ 21762306a36Sopenharmony_ci __le16 req_sz; /* size of each request payload */ 21862306a36Sopenharmony_ci __le16 req_cnt; /* count of reqs the buffer can hold */ 21962306a36Sopenharmony_ci __le16 status_sz; /* size of each status payload */ 22062306a36Sopenharmony_ci __le16 status_cnt; /* count of status the buffer can hold */ 22162306a36Sopenharmony_ci __le64 hosttime; /* seconds from Jan 1, 1970 (GMT) */ 22262306a36Sopenharmony_ci u8 partner_type; /* who sends this frame */ 22362306a36Sopenharmony_ci u8 reserved0[7]; 22462306a36Sopenharmony_ci __le32 partner_ver_major; 22562306a36Sopenharmony_ci __le32 partner_ver_minor; 22662306a36Sopenharmony_ci __le32 partner_ver_oem; 22762306a36Sopenharmony_ci __le32 partner_ver_build; 22862306a36Sopenharmony_ci __le32 extra_offset; /* NEW */ 22962306a36Sopenharmony_ci __le32 extra_size; /* NEW */ 23062306a36Sopenharmony_ci __le32 scratch_size; 23162306a36Sopenharmony_ci u32 reserved1; 23262306a36Sopenharmony_ci}; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistruct req_msg { 23562306a36Sopenharmony_ci __le16 tag; 23662306a36Sopenharmony_ci u8 lun; 23762306a36Sopenharmony_ci u8 target; 23862306a36Sopenharmony_ci u8 task_attr; 23962306a36Sopenharmony_ci u8 task_manage; 24062306a36Sopenharmony_ci u8 data_dir; 24162306a36Sopenharmony_ci u8 payload_sz; /* payload size in 4-byte, not used */ 24262306a36Sopenharmony_ci u8 cdb[STEX_CDB_LENGTH]; 24362306a36Sopenharmony_ci u32 variable[]; 24462306a36Sopenharmony_ci}; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistruct status_msg { 24762306a36Sopenharmony_ci __le16 tag; 24862306a36Sopenharmony_ci u8 lun; 24962306a36Sopenharmony_ci u8 target; 25062306a36Sopenharmony_ci u8 srb_status; 25162306a36Sopenharmony_ci u8 scsi_status; 25262306a36Sopenharmony_ci u8 reserved; 25362306a36Sopenharmony_ci u8 payload_sz; /* payload size in 4-byte */ 25462306a36Sopenharmony_ci u8 variable[STATUS_VAR_LEN]; 25562306a36Sopenharmony_ci}; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistruct ver_info { 25862306a36Sopenharmony_ci u32 major; 25962306a36Sopenharmony_ci u32 minor; 26062306a36Sopenharmony_ci u32 oem; 26162306a36Sopenharmony_ci u32 build; 26262306a36Sopenharmony_ci u32 reserved[2]; 26362306a36Sopenharmony_ci}; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistruct st_frame { 26662306a36Sopenharmony_ci u32 base[6]; 26762306a36Sopenharmony_ci u32 rom_addr; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci struct ver_info drv_ver; 27062306a36Sopenharmony_ci struct ver_info bios_ver; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci u32 bus; 27362306a36Sopenharmony_ci u32 slot; 27462306a36Sopenharmony_ci u32 irq_level; 27562306a36Sopenharmony_ci u32 irq_vec; 27662306a36Sopenharmony_ci u32 id; 27762306a36Sopenharmony_ci u32 subid; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci u32 dimm_size; 28062306a36Sopenharmony_ci u8 dimm_type; 28162306a36Sopenharmony_ci u8 reserved[3]; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci u32 channel; 28462306a36Sopenharmony_ci u32 reserved1; 28562306a36Sopenharmony_ci}; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cistruct st_drvver { 28862306a36Sopenharmony_ci u32 major; 28962306a36Sopenharmony_ci u32 minor; 29062306a36Sopenharmony_ci u32 oem; 29162306a36Sopenharmony_ci u32 build; 29262306a36Sopenharmony_ci u32 signature[2]; 29362306a36Sopenharmony_ci u8 console_id; 29462306a36Sopenharmony_ci u8 host_no; 29562306a36Sopenharmony_ci u8 reserved0[2]; 29662306a36Sopenharmony_ci u32 reserved[3]; 29762306a36Sopenharmony_ci}; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistruct st_ccb { 30062306a36Sopenharmony_ci struct req_msg *req; 30162306a36Sopenharmony_ci struct scsi_cmnd *cmd; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci void *sense_buffer; 30462306a36Sopenharmony_ci unsigned int sense_bufflen; 30562306a36Sopenharmony_ci int sg_count; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci u32 req_type; 30862306a36Sopenharmony_ci u8 srb_status; 30962306a36Sopenharmony_ci u8 scsi_status; 31062306a36Sopenharmony_ci u8 reserved[2]; 31162306a36Sopenharmony_ci}; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistruct st_hba { 31462306a36Sopenharmony_ci void __iomem *mmio_base; /* iomapped PCI memory space */ 31562306a36Sopenharmony_ci void *dma_mem; 31662306a36Sopenharmony_ci dma_addr_t dma_handle; 31762306a36Sopenharmony_ci size_t dma_size; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci struct Scsi_Host *host; 32062306a36Sopenharmony_ci struct pci_dev *pdev; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci struct req_msg * (*alloc_rq) (struct st_hba *); 32362306a36Sopenharmony_ci int (*map_sg)(struct st_hba *, struct req_msg *, struct st_ccb *); 32462306a36Sopenharmony_ci void (*send) (struct st_hba *, struct req_msg *, u16); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci u32 req_head; 32762306a36Sopenharmony_ci u32 req_tail; 32862306a36Sopenharmony_ci u32 status_head; 32962306a36Sopenharmony_ci u32 status_tail; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci struct status_msg *status_buffer; 33262306a36Sopenharmony_ci void *copy_buffer; /* temp buffer for driver-handled commands */ 33362306a36Sopenharmony_ci struct st_ccb *ccb; 33462306a36Sopenharmony_ci struct st_ccb *wait_ccb; 33562306a36Sopenharmony_ci __le32 *scratch; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci char work_q_name[20]; 33862306a36Sopenharmony_ci struct workqueue_struct *work_q; 33962306a36Sopenharmony_ci struct work_struct reset_work; 34062306a36Sopenharmony_ci wait_queue_head_t reset_waitq; 34162306a36Sopenharmony_ci unsigned int mu_status; 34262306a36Sopenharmony_ci unsigned int cardtype; 34362306a36Sopenharmony_ci int msi_enabled; 34462306a36Sopenharmony_ci int out_req_cnt; 34562306a36Sopenharmony_ci u32 extra_offset; 34662306a36Sopenharmony_ci u16 rq_count; 34762306a36Sopenharmony_ci u16 rq_size; 34862306a36Sopenharmony_ci u16 sts_count; 34962306a36Sopenharmony_ci u8 supports_pm; 35062306a36Sopenharmony_ci int msi_lock; 35162306a36Sopenharmony_ci}; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_cistruct st_card_info { 35462306a36Sopenharmony_ci struct req_msg * (*alloc_rq) (struct st_hba *); 35562306a36Sopenharmony_ci int (*map_sg)(struct st_hba *, struct req_msg *, struct st_ccb *); 35662306a36Sopenharmony_ci void (*send) (struct st_hba *, struct req_msg *, u16); 35762306a36Sopenharmony_ci unsigned int max_id; 35862306a36Sopenharmony_ci unsigned int max_lun; 35962306a36Sopenharmony_ci unsigned int max_channel; 36062306a36Sopenharmony_ci u16 rq_count; 36162306a36Sopenharmony_ci u16 rq_size; 36262306a36Sopenharmony_ci u16 sts_count; 36362306a36Sopenharmony_ci}; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic int S6flag; 36662306a36Sopenharmony_cistatic int stex_halt(struct notifier_block *nb, ulong event, void *buf); 36762306a36Sopenharmony_cistatic struct notifier_block stex_notifier = { 36862306a36Sopenharmony_ci stex_halt, NULL, 0 36962306a36Sopenharmony_ci}; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic int msi; 37262306a36Sopenharmony_cimodule_param(msi, int, 0); 37362306a36Sopenharmony_ciMODULE_PARM_DESC(msi, "Enable Message Signaled Interrupts(0=off, 1=on)"); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_cistatic const char console_inq_page[] = 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci 0x03,0x00,0x03,0x03,0xFA,0x00,0x00,0x30, 37862306a36Sopenharmony_ci 0x50,0x72,0x6F,0x6D,0x69,0x73,0x65,0x20, /* "Promise " */ 37962306a36Sopenharmony_ci 0x52,0x41,0x49,0x44,0x20,0x43,0x6F,0x6E, /* "RAID Con" */ 38062306a36Sopenharmony_ci 0x73,0x6F,0x6C,0x65,0x20,0x20,0x20,0x20, /* "sole " */ 38162306a36Sopenharmony_ci 0x31,0x2E,0x30,0x30,0x20,0x20,0x20,0x20, /* "1.00 " */ 38262306a36Sopenharmony_ci 0x53,0x58,0x2F,0x52,0x53,0x41,0x46,0x2D, /* "SX/RSAF-" */ 38362306a36Sopenharmony_ci 0x54,0x45,0x31,0x2E,0x30,0x30,0x20,0x20, /* "TE1.00 " */ 38462306a36Sopenharmony_ci 0x0C,0x20,0x20,0x20,0x20,0x20,0x20,0x20 38562306a36Sopenharmony_ci}; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ciMODULE_AUTHOR("Ed Lin"); 38862306a36Sopenharmony_ciMODULE_DESCRIPTION("Promise Technology SuperTrak EX Controllers"); 38962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 39062306a36Sopenharmony_ciMODULE_VERSION(ST_DRIVER_VERSION); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cistatic struct status_msg *stex_get_status(struct st_hba *hba) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci struct status_msg *status = hba->status_buffer + hba->status_tail; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci ++hba->status_tail; 39762306a36Sopenharmony_ci hba->status_tail %= hba->sts_count+1; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci return status; 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistatic void stex_invalid_field(struct scsi_cmnd *cmd, 40362306a36Sopenharmony_ci void (*done)(struct scsi_cmnd *)) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci /* "Invalid field in cdb" */ 40662306a36Sopenharmony_ci scsi_build_sense(cmd, 0, ILLEGAL_REQUEST, 0x24, 0x0); 40762306a36Sopenharmony_ci done(cmd); 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic struct req_msg *stex_alloc_req(struct st_hba *hba) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci struct req_msg *req = hba->dma_mem + hba->req_head * hba->rq_size; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci ++hba->req_head; 41562306a36Sopenharmony_ci hba->req_head %= hba->rq_count+1; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci return req; 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_cistatic struct req_msg *stex_ss_alloc_req(struct st_hba *hba) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci return (struct req_msg *)(hba->dma_mem + 42362306a36Sopenharmony_ci hba->req_head * hba->rq_size + sizeof(struct st_msg_header)); 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistatic int stex_map_sg(struct st_hba *hba, 42762306a36Sopenharmony_ci struct req_msg *req, struct st_ccb *ccb) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci struct scsi_cmnd *cmd; 43062306a36Sopenharmony_ci struct scatterlist *sg; 43162306a36Sopenharmony_ci struct st_sgtable *dst; 43262306a36Sopenharmony_ci struct st_sgitem *table; 43362306a36Sopenharmony_ci int i, nseg; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci cmd = ccb->cmd; 43662306a36Sopenharmony_ci nseg = scsi_dma_map(cmd); 43762306a36Sopenharmony_ci BUG_ON(nseg < 0); 43862306a36Sopenharmony_ci if (nseg) { 43962306a36Sopenharmony_ci dst = (struct st_sgtable *)req->variable; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci ccb->sg_count = nseg; 44262306a36Sopenharmony_ci dst->sg_count = cpu_to_le16((u16)nseg); 44362306a36Sopenharmony_ci dst->max_sg_count = cpu_to_le16(hba->host->sg_tablesize); 44462306a36Sopenharmony_ci dst->sz_in_byte = cpu_to_le32(scsi_bufflen(cmd)); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci table = (struct st_sgitem *)(dst + 1); 44762306a36Sopenharmony_ci scsi_for_each_sg(cmd, sg, nseg, i) { 44862306a36Sopenharmony_ci table[i].count = cpu_to_le32((u32)sg_dma_len(sg)); 44962306a36Sopenharmony_ci table[i].addr = cpu_to_le64(sg_dma_address(sg)); 45062306a36Sopenharmony_ci table[i].ctrl = SG_CF_64B | SG_CF_HOST; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci table[--i].ctrl |= SG_CF_EOT; 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci return nseg; 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic int stex_ss_map_sg(struct st_hba *hba, 45962306a36Sopenharmony_ci struct req_msg *req, struct st_ccb *ccb) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci struct scsi_cmnd *cmd; 46262306a36Sopenharmony_ci struct scatterlist *sg; 46362306a36Sopenharmony_ci struct st_sgtable *dst; 46462306a36Sopenharmony_ci struct st_ss_sgitem *table; 46562306a36Sopenharmony_ci int i, nseg; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci cmd = ccb->cmd; 46862306a36Sopenharmony_ci nseg = scsi_dma_map(cmd); 46962306a36Sopenharmony_ci BUG_ON(nseg < 0); 47062306a36Sopenharmony_ci if (nseg) { 47162306a36Sopenharmony_ci dst = (struct st_sgtable *)req->variable; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci ccb->sg_count = nseg; 47462306a36Sopenharmony_ci dst->sg_count = cpu_to_le16((u16)nseg); 47562306a36Sopenharmony_ci dst->max_sg_count = cpu_to_le16(hba->host->sg_tablesize); 47662306a36Sopenharmony_ci dst->sz_in_byte = cpu_to_le32(scsi_bufflen(cmd)); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci table = (struct st_ss_sgitem *)(dst + 1); 47962306a36Sopenharmony_ci scsi_for_each_sg(cmd, sg, nseg, i) { 48062306a36Sopenharmony_ci table[i].count = cpu_to_le32((u32)sg_dma_len(sg)); 48162306a36Sopenharmony_ci table[i].addr = 48262306a36Sopenharmony_ci cpu_to_le32(sg_dma_address(sg) & 0xffffffff); 48362306a36Sopenharmony_ci table[i].addr_hi = 48462306a36Sopenharmony_ci cpu_to_le32((sg_dma_address(sg) >> 16) >> 16); 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci return nseg; 48962306a36Sopenharmony_ci} 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_cistatic void stex_controller_info(struct st_hba *hba, struct st_ccb *ccb) 49262306a36Sopenharmony_ci{ 49362306a36Sopenharmony_ci struct st_frame *p; 49462306a36Sopenharmony_ci size_t count = sizeof(struct st_frame); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci p = hba->copy_buffer; 49762306a36Sopenharmony_ci scsi_sg_copy_to_buffer(ccb->cmd, p, count); 49862306a36Sopenharmony_ci memset(p->base, 0, sizeof(u32)*6); 49962306a36Sopenharmony_ci *(unsigned long *)(p->base) = pci_resource_start(hba->pdev, 0); 50062306a36Sopenharmony_ci p->rom_addr = 0; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci p->drv_ver.major = ST_VER_MAJOR; 50362306a36Sopenharmony_ci p->drv_ver.minor = ST_VER_MINOR; 50462306a36Sopenharmony_ci p->drv_ver.oem = ST_OEM; 50562306a36Sopenharmony_ci p->drv_ver.build = ST_BUILD_VER; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci p->bus = hba->pdev->bus->number; 50862306a36Sopenharmony_ci p->slot = hba->pdev->devfn; 50962306a36Sopenharmony_ci p->irq_level = 0; 51062306a36Sopenharmony_ci p->irq_vec = hba->pdev->irq; 51162306a36Sopenharmony_ci p->id = hba->pdev->vendor << 16 | hba->pdev->device; 51262306a36Sopenharmony_ci p->subid = 51362306a36Sopenharmony_ci hba->pdev->subsystem_vendor << 16 | hba->pdev->subsystem_device; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci scsi_sg_copy_from_buffer(ccb->cmd, p, count); 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_cistatic void 51962306a36Sopenharmony_cistex_send_cmd(struct st_hba *hba, struct req_msg *req, u16 tag) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci req->tag = cpu_to_le16(tag); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci hba->ccb[tag].req = req; 52462306a36Sopenharmony_ci hba->out_req_cnt++; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci writel(hba->req_head, hba->mmio_base + IMR0); 52762306a36Sopenharmony_ci writel(MU_INBOUND_DOORBELL_REQHEADCHANGED, hba->mmio_base + IDBL); 52862306a36Sopenharmony_ci readl(hba->mmio_base + IDBL); /* flush */ 52962306a36Sopenharmony_ci} 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cistatic void 53262306a36Sopenharmony_cistex_ss_send_cmd(struct st_hba *hba, struct req_msg *req, u16 tag) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci struct scsi_cmnd *cmd; 53562306a36Sopenharmony_ci struct st_msg_header *msg_h; 53662306a36Sopenharmony_ci dma_addr_t addr; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci req->tag = cpu_to_le16(tag); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci hba->ccb[tag].req = req; 54162306a36Sopenharmony_ci hba->out_req_cnt++; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci cmd = hba->ccb[tag].cmd; 54462306a36Sopenharmony_ci msg_h = (struct st_msg_header *)req - 1; 54562306a36Sopenharmony_ci if (likely(cmd)) { 54662306a36Sopenharmony_ci msg_h->channel = (u8)cmd->device->channel; 54762306a36Sopenharmony_ci msg_h->timeout = cpu_to_le16(scsi_cmd_to_rq(cmd)->timeout / HZ); 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci addr = hba->dma_handle + hba->req_head * hba->rq_size; 55062306a36Sopenharmony_ci addr += (hba->ccb[tag].sg_count+4)/11; 55162306a36Sopenharmony_ci msg_h->handle = cpu_to_le64(addr); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci ++hba->req_head; 55462306a36Sopenharmony_ci hba->req_head %= hba->rq_count+1; 55562306a36Sopenharmony_ci if (hba->cardtype == st_P3) { 55662306a36Sopenharmony_ci writel((addr >> 16) >> 16, hba->mmio_base + YH2I_REQ_HI); 55762306a36Sopenharmony_ci writel(addr, hba->mmio_base + YH2I_REQ); 55862306a36Sopenharmony_ci } else { 55962306a36Sopenharmony_ci writel((addr >> 16) >> 16, hba->mmio_base + YH2I_REQ_HI); 56062306a36Sopenharmony_ci readl(hba->mmio_base + YH2I_REQ_HI); /* flush */ 56162306a36Sopenharmony_ci writel(addr, hba->mmio_base + YH2I_REQ); 56262306a36Sopenharmony_ci readl(hba->mmio_base + YH2I_REQ); /* flush */ 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci} 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_cistatic void return_abnormal_state(struct st_hba *hba, int status) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci struct st_ccb *ccb; 56962306a36Sopenharmony_ci unsigned long flags; 57062306a36Sopenharmony_ci u16 tag; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci spin_lock_irqsave(hba->host->host_lock, flags); 57362306a36Sopenharmony_ci for (tag = 0; tag < hba->host->can_queue; tag++) { 57462306a36Sopenharmony_ci ccb = &hba->ccb[tag]; 57562306a36Sopenharmony_ci if (ccb->req == NULL) 57662306a36Sopenharmony_ci continue; 57762306a36Sopenharmony_ci ccb->req = NULL; 57862306a36Sopenharmony_ci if (ccb->cmd) { 57962306a36Sopenharmony_ci scsi_dma_unmap(ccb->cmd); 58062306a36Sopenharmony_ci ccb->cmd->result = status << 16; 58162306a36Sopenharmony_ci scsi_done(ccb->cmd); 58262306a36Sopenharmony_ci ccb->cmd = NULL; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_cistatic int 58862306a36Sopenharmony_cistex_slave_config(struct scsi_device *sdev) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci sdev->use_10_for_rw = 1; 59162306a36Sopenharmony_ci sdev->use_10_for_ms = 1; 59262306a36Sopenharmony_ci blk_queue_rq_timeout(sdev->request_queue, 60 * HZ); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci return 0; 59562306a36Sopenharmony_ci} 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_cistatic int stex_queuecommand_lck(struct scsi_cmnd *cmd) 59862306a36Sopenharmony_ci{ 59962306a36Sopenharmony_ci void (*done)(struct scsi_cmnd *) = scsi_done; 60062306a36Sopenharmony_ci struct st_hba *hba; 60162306a36Sopenharmony_ci struct Scsi_Host *host; 60262306a36Sopenharmony_ci unsigned int id, lun; 60362306a36Sopenharmony_ci struct req_msg *req; 60462306a36Sopenharmony_ci u16 tag; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci host = cmd->device->host; 60762306a36Sopenharmony_ci id = cmd->device->id; 60862306a36Sopenharmony_ci lun = cmd->device->lun; 60962306a36Sopenharmony_ci hba = (struct st_hba *) &host->hostdata[0]; 61062306a36Sopenharmony_ci if (hba->mu_status == MU_STATE_NOCONNECT) { 61162306a36Sopenharmony_ci cmd->result = DID_NO_CONNECT; 61262306a36Sopenharmony_ci done(cmd); 61362306a36Sopenharmony_ci return 0; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci if (unlikely(hba->mu_status != MU_STATE_STARTED)) 61662306a36Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci switch (cmd->cmnd[0]) { 61962306a36Sopenharmony_ci case MODE_SENSE_10: 62062306a36Sopenharmony_ci { 62162306a36Sopenharmony_ci static char ms10_caching_page[12] = 62262306a36Sopenharmony_ci { 0, 0x12, 0, 0, 0, 0, 0, 0, 0x8, 0xa, 0x4, 0 }; 62362306a36Sopenharmony_ci unsigned char page; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci page = cmd->cmnd[2] & 0x3f; 62662306a36Sopenharmony_ci if (page == 0x8 || page == 0x3f) { 62762306a36Sopenharmony_ci scsi_sg_copy_from_buffer(cmd, ms10_caching_page, 62862306a36Sopenharmony_ci sizeof(ms10_caching_page)); 62962306a36Sopenharmony_ci cmd->result = DID_OK << 16; 63062306a36Sopenharmony_ci done(cmd); 63162306a36Sopenharmony_ci } else 63262306a36Sopenharmony_ci stex_invalid_field(cmd, done); 63362306a36Sopenharmony_ci return 0; 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci case REPORT_LUNS: 63662306a36Sopenharmony_ci /* 63762306a36Sopenharmony_ci * The shasta firmware does not report actual luns in the 63862306a36Sopenharmony_ci * target, so fail the command to force sequential lun scan. 63962306a36Sopenharmony_ci * Also, the console device does not support this command. 64062306a36Sopenharmony_ci */ 64162306a36Sopenharmony_ci if (hba->cardtype == st_shasta || id == host->max_id - 1) { 64262306a36Sopenharmony_ci stex_invalid_field(cmd, done); 64362306a36Sopenharmony_ci return 0; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci break; 64662306a36Sopenharmony_ci case TEST_UNIT_READY: 64762306a36Sopenharmony_ci if (id == host->max_id - 1) { 64862306a36Sopenharmony_ci cmd->result = DID_OK << 16; 64962306a36Sopenharmony_ci done(cmd); 65062306a36Sopenharmony_ci return 0; 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci break; 65362306a36Sopenharmony_ci case INQUIRY: 65462306a36Sopenharmony_ci if (lun >= host->max_lun) { 65562306a36Sopenharmony_ci cmd->result = DID_NO_CONNECT << 16; 65662306a36Sopenharmony_ci done(cmd); 65762306a36Sopenharmony_ci return 0; 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci if (id != host->max_id - 1) 66062306a36Sopenharmony_ci break; 66162306a36Sopenharmony_ci if (!lun && !cmd->device->channel && 66262306a36Sopenharmony_ci (cmd->cmnd[1] & INQUIRY_EVPD) == 0) { 66362306a36Sopenharmony_ci scsi_sg_copy_from_buffer(cmd, (void *)console_inq_page, 66462306a36Sopenharmony_ci sizeof(console_inq_page)); 66562306a36Sopenharmony_ci cmd->result = DID_OK << 16; 66662306a36Sopenharmony_ci done(cmd); 66762306a36Sopenharmony_ci } else 66862306a36Sopenharmony_ci stex_invalid_field(cmd, done); 66962306a36Sopenharmony_ci return 0; 67062306a36Sopenharmony_ci case PASSTHRU_CMD: 67162306a36Sopenharmony_ci if (cmd->cmnd[1] == PASSTHRU_GET_DRVVER) { 67262306a36Sopenharmony_ci const struct st_drvver ver = { 67362306a36Sopenharmony_ci .major = ST_VER_MAJOR, 67462306a36Sopenharmony_ci .minor = ST_VER_MINOR, 67562306a36Sopenharmony_ci .oem = ST_OEM, 67662306a36Sopenharmony_ci .build = ST_BUILD_VER, 67762306a36Sopenharmony_ci .signature[0] = PASSTHRU_SIGNATURE, 67862306a36Sopenharmony_ci .console_id = host->max_id - 1, 67962306a36Sopenharmony_ci .host_no = hba->host->host_no, 68062306a36Sopenharmony_ci }; 68162306a36Sopenharmony_ci size_t cp_len = sizeof(ver); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci cp_len = scsi_sg_copy_from_buffer(cmd, &ver, cp_len); 68462306a36Sopenharmony_ci if (sizeof(ver) == cp_len) 68562306a36Sopenharmony_ci cmd->result = DID_OK << 16; 68662306a36Sopenharmony_ci else 68762306a36Sopenharmony_ci cmd->result = DID_ERROR << 16; 68862306a36Sopenharmony_ci done(cmd); 68962306a36Sopenharmony_ci return 0; 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci break; 69262306a36Sopenharmony_ci default: 69362306a36Sopenharmony_ci break; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci tag = scsi_cmd_to_rq(cmd)->tag; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci if (unlikely(tag >= host->can_queue)) 69962306a36Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci req = hba->alloc_rq(hba); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci req->lun = lun; 70462306a36Sopenharmony_ci req->target = id; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci /* cdb */ 70762306a36Sopenharmony_ci memcpy(req->cdb, cmd->cmnd, STEX_CDB_LENGTH); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci if (cmd->sc_data_direction == DMA_FROM_DEVICE) 71062306a36Sopenharmony_ci req->data_dir = MSG_DATA_DIR_IN; 71162306a36Sopenharmony_ci else if (cmd->sc_data_direction == DMA_TO_DEVICE) 71262306a36Sopenharmony_ci req->data_dir = MSG_DATA_DIR_OUT; 71362306a36Sopenharmony_ci else 71462306a36Sopenharmony_ci req->data_dir = MSG_DATA_DIR_ND; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci hba->ccb[tag].cmd = cmd; 71762306a36Sopenharmony_ci hba->ccb[tag].sense_bufflen = SCSI_SENSE_BUFFERSIZE; 71862306a36Sopenharmony_ci hba->ccb[tag].sense_buffer = cmd->sense_buffer; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci if (!hba->map_sg(hba, req, &hba->ccb[tag])) { 72162306a36Sopenharmony_ci hba->ccb[tag].sg_count = 0; 72262306a36Sopenharmony_ci memset(&req->variable[0], 0, 8); 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci hba->send(hba, req, tag); 72662306a36Sopenharmony_ci return 0; 72762306a36Sopenharmony_ci} 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_cistatic DEF_SCSI_QCMD(stex_queuecommand) 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic void stex_scsi_done(struct st_ccb *ccb) 73262306a36Sopenharmony_ci{ 73362306a36Sopenharmony_ci struct scsi_cmnd *cmd = ccb->cmd; 73462306a36Sopenharmony_ci int result; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci if (ccb->srb_status == SRB_STATUS_SUCCESS || ccb->srb_status == 0) { 73762306a36Sopenharmony_ci result = ccb->scsi_status; 73862306a36Sopenharmony_ci switch (ccb->scsi_status) { 73962306a36Sopenharmony_ci case SAM_STAT_GOOD: 74062306a36Sopenharmony_ci result |= DID_OK << 16; 74162306a36Sopenharmony_ci break; 74262306a36Sopenharmony_ci case SAM_STAT_CHECK_CONDITION: 74362306a36Sopenharmony_ci result |= DID_OK << 16; 74462306a36Sopenharmony_ci break; 74562306a36Sopenharmony_ci case SAM_STAT_BUSY: 74662306a36Sopenharmony_ci result |= DID_BUS_BUSY << 16; 74762306a36Sopenharmony_ci break; 74862306a36Sopenharmony_ci default: 74962306a36Sopenharmony_ci result |= DID_ERROR << 16; 75062306a36Sopenharmony_ci break; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci else if (ccb->srb_status & SRB_SEE_SENSE) 75462306a36Sopenharmony_ci result = SAM_STAT_CHECK_CONDITION; 75562306a36Sopenharmony_ci else switch (ccb->srb_status) { 75662306a36Sopenharmony_ci case SRB_STATUS_SELECTION_TIMEOUT: 75762306a36Sopenharmony_ci result = DID_NO_CONNECT << 16; 75862306a36Sopenharmony_ci break; 75962306a36Sopenharmony_ci case SRB_STATUS_BUSY: 76062306a36Sopenharmony_ci result = DID_BUS_BUSY << 16; 76162306a36Sopenharmony_ci break; 76262306a36Sopenharmony_ci case SRB_STATUS_INVALID_REQUEST: 76362306a36Sopenharmony_ci case SRB_STATUS_ERROR: 76462306a36Sopenharmony_ci default: 76562306a36Sopenharmony_ci result = DID_ERROR << 16; 76662306a36Sopenharmony_ci break; 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci cmd->result = result; 77062306a36Sopenharmony_ci scsi_done(cmd); 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_cistatic void stex_copy_data(struct st_ccb *ccb, 77462306a36Sopenharmony_ci struct status_msg *resp, unsigned int variable) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci if (resp->scsi_status != SAM_STAT_GOOD) { 77762306a36Sopenharmony_ci if (ccb->sense_buffer != NULL) 77862306a36Sopenharmony_ci memcpy(ccb->sense_buffer, resp->variable, 77962306a36Sopenharmony_ci min(variable, ccb->sense_bufflen)); 78062306a36Sopenharmony_ci return; 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci if (ccb->cmd == NULL) 78462306a36Sopenharmony_ci return; 78562306a36Sopenharmony_ci scsi_sg_copy_from_buffer(ccb->cmd, resp->variable, variable); 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_cistatic void stex_check_cmd(struct st_hba *hba, 78962306a36Sopenharmony_ci struct st_ccb *ccb, struct status_msg *resp) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci if (ccb->cmd->cmnd[0] == MGT_CMD && 79262306a36Sopenharmony_ci resp->scsi_status != SAM_STAT_CHECK_CONDITION) 79362306a36Sopenharmony_ci scsi_set_resid(ccb->cmd, scsi_bufflen(ccb->cmd) - 79462306a36Sopenharmony_ci le32_to_cpu(*(__le32 *)&resp->variable[0])); 79562306a36Sopenharmony_ci} 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_cistatic void stex_mu_intr(struct st_hba *hba, u32 doorbell) 79862306a36Sopenharmony_ci{ 79962306a36Sopenharmony_ci void __iomem *base = hba->mmio_base; 80062306a36Sopenharmony_ci struct status_msg *resp; 80162306a36Sopenharmony_ci struct st_ccb *ccb; 80262306a36Sopenharmony_ci unsigned int size; 80362306a36Sopenharmony_ci u16 tag; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci if (unlikely(!(doorbell & MU_OUTBOUND_DOORBELL_STATUSHEADCHANGED))) 80662306a36Sopenharmony_ci return; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci /* status payloads */ 80962306a36Sopenharmony_ci hba->status_head = readl(base + OMR1); 81062306a36Sopenharmony_ci if (unlikely(hba->status_head > hba->sts_count)) { 81162306a36Sopenharmony_ci printk(KERN_WARNING DRV_NAME "(%s): invalid status head\n", 81262306a36Sopenharmony_ci pci_name(hba->pdev)); 81362306a36Sopenharmony_ci return; 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci /* 81762306a36Sopenharmony_ci * it's not a valid status payload if: 81862306a36Sopenharmony_ci * 1. there are no pending requests(e.g. during init stage) 81962306a36Sopenharmony_ci * 2. there are some pending requests, but the controller is in 82062306a36Sopenharmony_ci * reset status, and its type is not st_yosemite 82162306a36Sopenharmony_ci * firmware of st_yosemite in reset status will return pending requests 82262306a36Sopenharmony_ci * to driver, so we allow it to pass 82362306a36Sopenharmony_ci */ 82462306a36Sopenharmony_ci if (unlikely(hba->out_req_cnt <= 0 || 82562306a36Sopenharmony_ci (hba->mu_status == MU_STATE_RESETTING && 82662306a36Sopenharmony_ci hba->cardtype != st_yosemite))) { 82762306a36Sopenharmony_ci hba->status_tail = hba->status_head; 82862306a36Sopenharmony_ci goto update_status; 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci while (hba->status_tail != hba->status_head) { 83262306a36Sopenharmony_ci resp = stex_get_status(hba); 83362306a36Sopenharmony_ci tag = le16_to_cpu(resp->tag); 83462306a36Sopenharmony_ci if (unlikely(tag >= hba->host->can_queue)) { 83562306a36Sopenharmony_ci printk(KERN_WARNING DRV_NAME 83662306a36Sopenharmony_ci "(%s): invalid tag\n", pci_name(hba->pdev)); 83762306a36Sopenharmony_ci continue; 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci hba->out_req_cnt--; 84162306a36Sopenharmony_ci ccb = &hba->ccb[tag]; 84262306a36Sopenharmony_ci if (unlikely(hba->wait_ccb == ccb)) 84362306a36Sopenharmony_ci hba->wait_ccb = NULL; 84462306a36Sopenharmony_ci if (unlikely(ccb->req == NULL)) { 84562306a36Sopenharmony_ci printk(KERN_WARNING DRV_NAME 84662306a36Sopenharmony_ci "(%s): lagging req\n", pci_name(hba->pdev)); 84762306a36Sopenharmony_ci continue; 84862306a36Sopenharmony_ci } 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci size = resp->payload_sz * sizeof(u32); /* payload size */ 85162306a36Sopenharmony_ci if (unlikely(size < sizeof(*resp) - STATUS_VAR_LEN || 85262306a36Sopenharmony_ci size > sizeof(*resp))) { 85362306a36Sopenharmony_ci printk(KERN_WARNING DRV_NAME "(%s): bad status size\n", 85462306a36Sopenharmony_ci pci_name(hba->pdev)); 85562306a36Sopenharmony_ci } else { 85662306a36Sopenharmony_ci size -= sizeof(*resp) - STATUS_VAR_LEN; /* copy size */ 85762306a36Sopenharmony_ci if (size) 85862306a36Sopenharmony_ci stex_copy_data(ccb, resp, size); 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci ccb->req = NULL; 86262306a36Sopenharmony_ci ccb->srb_status = resp->srb_status; 86362306a36Sopenharmony_ci ccb->scsi_status = resp->scsi_status; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci if (likely(ccb->cmd != NULL)) { 86662306a36Sopenharmony_ci if (hba->cardtype == st_yosemite) 86762306a36Sopenharmony_ci stex_check_cmd(hba, ccb, resp); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci if (unlikely(ccb->cmd->cmnd[0] == PASSTHRU_CMD && 87062306a36Sopenharmony_ci ccb->cmd->cmnd[1] == PASSTHRU_GET_ADAPTER)) 87162306a36Sopenharmony_ci stex_controller_info(hba, ccb); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci scsi_dma_unmap(ccb->cmd); 87462306a36Sopenharmony_ci stex_scsi_done(ccb); 87562306a36Sopenharmony_ci } else 87662306a36Sopenharmony_ci ccb->req_type = 0; 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ciupdate_status: 88062306a36Sopenharmony_ci writel(hba->status_head, base + IMR1); 88162306a36Sopenharmony_ci readl(base + IMR1); /* flush */ 88262306a36Sopenharmony_ci} 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_cistatic irqreturn_t stex_intr(int irq, void *__hba) 88562306a36Sopenharmony_ci{ 88662306a36Sopenharmony_ci struct st_hba *hba = __hba; 88762306a36Sopenharmony_ci void __iomem *base = hba->mmio_base; 88862306a36Sopenharmony_ci u32 data; 88962306a36Sopenharmony_ci unsigned long flags; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci spin_lock_irqsave(hba->host->host_lock, flags); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci data = readl(base + ODBL); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci if (data && data != 0xffffffff) { 89662306a36Sopenharmony_ci /* clear the interrupt */ 89762306a36Sopenharmony_ci writel(data, base + ODBL); 89862306a36Sopenharmony_ci readl(base + ODBL); /* flush */ 89962306a36Sopenharmony_ci stex_mu_intr(hba, data); 90062306a36Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 90162306a36Sopenharmony_ci if (unlikely(data & MU_OUTBOUND_DOORBELL_REQUEST_RESET && 90262306a36Sopenharmony_ci hba->cardtype == st_shasta)) 90362306a36Sopenharmony_ci queue_work(hba->work_q, &hba->reset_work); 90462306a36Sopenharmony_ci return IRQ_HANDLED; 90562306a36Sopenharmony_ci } 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci return IRQ_NONE; 91062306a36Sopenharmony_ci} 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_cistatic void stex_ss_mu_intr(struct st_hba *hba) 91362306a36Sopenharmony_ci{ 91462306a36Sopenharmony_ci struct status_msg *resp; 91562306a36Sopenharmony_ci struct st_ccb *ccb; 91662306a36Sopenharmony_ci __le32 *scratch; 91762306a36Sopenharmony_ci unsigned int size; 91862306a36Sopenharmony_ci int count = 0; 91962306a36Sopenharmony_ci u32 value; 92062306a36Sopenharmony_ci u16 tag; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci if (unlikely(hba->out_req_cnt <= 0 || 92362306a36Sopenharmony_ci hba->mu_status == MU_STATE_RESETTING)) 92462306a36Sopenharmony_ci return; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci while (count < hba->sts_count) { 92762306a36Sopenharmony_ci scratch = hba->scratch + hba->status_tail; 92862306a36Sopenharmony_ci value = le32_to_cpu(*scratch); 92962306a36Sopenharmony_ci if (unlikely(!(value & SS_STS_NORMAL))) 93062306a36Sopenharmony_ci return; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci resp = hba->status_buffer + hba->status_tail; 93362306a36Sopenharmony_ci *scratch = 0; 93462306a36Sopenharmony_ci ++count; 93562306a36Sopenharmony_ci ++hba->status_tail; 93662306a36Sopenharmony_ci hba->status_tail %= hba->sts_count+1; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci tag = (u16)value; 93962306a36Sopenharmony_ci if (unlikely(tag >= hba->host->can_queue)) { 94062306a36Sopenharmony_ci printk(KERN_WARNING DRV_NAME 94162306a36Sopenharmony_ci "(%s): invalid tag\n", pci_name(hba->pdev)); 94262306a36Sopenharmony_ci continue; 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci hba->out_req_cnt--; 94662306a36Sopenharmony_ci ccb = &hba->ccb[tag]; 94762306a36Sopenharmony_ci if (unlikely(hba->wait_ccb == ccb)) 94862306a36Sopenharmony_ci hba->wait_ccb = NULL; 94962306a36Sopenharmony_ci if (unlikely(ccb->req == NULL)) { 95062306a36Sopenharmony_ci printk(KERN_WARNING DRV_NAME 95162306a36Sopenharmony_ci "(%s): lagging req\n", pci_name(hba->pdev)); 95262306a36Sopenharmony_ci continue; 95362306a36Sopenharmony_ci } 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci ccb->req = NULL; 95662306a36Sopenharmony_ci if (likely(value & SS_STS_DONE)) { /* normal case */ 95762306a36Sopenharmony_ci ccb->srb_status = SRB_STATUS_SUCCESS; 95862306a36Sopenharmony_ci ccb->scsi_status = SAM_STAT_GOOD; 95962306a36Sopenharmony_ci } else { 96062306a36Sopenharmony_ci ccb->srb_status = resp->srb_status; 96162306a36Sopenharmony_ci ccb->scsi_status = resp->scsi_status; 96262306a36Sopenharmony_ci size = resp->payload_sz * sizeof(u32); 96362306a36Sopenharmony_ci if (unlikely(size < sizeof(*resp) - STATUS_VAR_LEN || 96462306a36Sopenharmony_ci size > sizeof(*resp))) { 96562306a36Sopenharmony_ci printk(KERN_WARNING DRV_NAME 96662306a36Sopenharmony_ci "(%s): bad status size\n", 96762306a36Sopenharmony_ci pci_name(hba->pdev)); 96862306a36Sopenharmony_ci } else { 96962306a36Sopenharmony_ci size -= sizeof(*resp) - STATUS_VAR_LEN; 97062306a36Sopenharmony_ci if (size) 97162306a36Sopenharmony_ci stex_copy_data(ccb, resp, size); 97262306a36Sopenharmony_ci } 97362306a36Sopenharmony_ci if (likely(ccb->cmd != NULL)) 97462306a36Sopenharmony_ci stex_check_cmd(hba, ccb, resp); 97562306a36Sopenharmony_ci } 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci if (likely(ccb->cmd != NULL)) { 97862306a36Sopenharmony_ci scsi_dma_unmap(ccb->cmd); 97962306a36Sopenharmony_ci stex_scsi_done(ccb); 98062306a36Sopenharmony_ci } else 98162306a36Sopenharmony_ci ccb->req_type = 0; 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci} 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_cistatic irqreturn_t stex_ss_intr(int irq, void *__hba) 98662306a36Sopenharmony_ci{ 98762306a36Sopenharmony_ci struct st_hba *hba = __hba; 98862306a36Sopenharmony_ci void __iomem *base = hba->mmio_base; 98962306a36Sopenharmony_ci u32 data; 99062306a36Sopenharmony_ci unsigned long flags; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci spin_lock_irqsave(hba->host->host_lock, flags); 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci if (hba->cardtype == st_yel) { 99562306a36Sopenharmony_ci data = readl(base + YI2H_INT); 99662306a36Sopenharmony_ci if (data && data != 0xffffffff) { 99762306a36Sopenharmony_ci /* clear the interrupt */ 99862306a36Sopenharmony_ci writel(data, base + YI2H_INT_C); 99962306a36Sopenharmony_ci stex_ss_mu_intr(hba); 100062306a36Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 100162306a36Sopenharmony_ci if (unlikely(data & SS_I2H_REQUEST_RESET)) 100262306a36Sopenharmony_ci queue_work(hba->work_q, &hba->reset_work); 100362306a36Sopenharmony_ci return IRQ_HANDLED; 100462306a36Sopenharmony_ci } 100562306a36Sopenharmony_ci } else { 100662306a36Sopenharmony_ci data = readl(base + PSCRATCH4); 100762306a36Sopenharmony_ci if (data != 0xffffffff) { 100862306a36Sopenharmony_ci if (data != 0) { 100962306a36Sopenharmony_ci /* clear the interrupt */ 101062306a36Sopenharmony_ci writel(data, base + PSCRATCH1); 101162306a36Sopenharmony_ci writel((1 << 22), base + YH2I_INT); 101262306a36Sopenharmony_ci } 101362306a36Sopenharmony_ci stex_ss_mu_intr(hba); 101462306a36Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 101562306a36Sopenharmony_ci if (unlikely(data & SS_I2H_REQUEST_RESET)) 101662306a36Sopenharmony_ci queue_work(hba->work_q, &hba->reset_work); 101762306a36Sopenharmony_ci return IRQ_HANDLED; 101862306a36Sopenharmony_ci } 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci return IRQ_NONE; 102462306a36Sopenharmony_ci} 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_cistatic int stex_common_handshake(struct st_hba *hba) 102762306a36Sopenharmony_ci{ 102862306a36Sopenharmony_ci void __iomem *base = hba->mmio_base; 102962306a36Sopenharmony_ci struct handshake_frame *h; 103062306a36Sopenharmony_ci dma_addr_t status_phys; 103162306a36Sopenharmony_ci u32 data; 103262306a36Sopenharmony_ci unsigned long before; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci if (readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE) { 103562306a36Sopenharmony_ci writel(MU_INBOUND_DOORBELL_HANDSHAKE, base + IDBL); 103662306a36Sopenharmony_ci readl(base + IDBL); 103762306a36Sopenharmony_ci before = jiffies; 103862306a36Sopenharmony_ci while (readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE) { 103962306a36Sopenharmony_ci if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) { 104062306a36Sopenharmony_ci printk(KERN_ERR DRV_NAME 104162306a36Sopenharmony_ci "(%s): no handshake signature\n", 104262306a36Sopenharmony_ci pci_name(hba->pdev)); 104362306a36Sopenharmony_ci return -1; 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci rmb(); 104662306a36Sopenharmony_ci msleep(1); 104762306a36Sopenharmony_ci } 104862306a36Sopenharmony_ci } 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci udelay(10); 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci data = readl(base + OMR1); 105362306a36Sopenharmony_ci if ((data & 0xffff0000) == MU_HANDSHAKE_SIGNATURE_HALF) { 105462306a36Sopenharmony_ci data &= 0x0000ffff; 105562306a36Sopenharmony_ci if (hba->host->can_queue > data) { 105662306a36Sopenharmony_ci hba->host->can_queue = data; 105762306a36Sopenharmony_ci hba->host->cmd_per_lun = data; 105862306a36Sopenharmony_ci } 105962306a36Sopenharmony_ci } 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci h = (struct handshake_frame *)hba->status_buffer; 106262306a36Sopenharmony_ci h->rb_phy = cpu_to_le64(hba->dma_handle); 106362306a36Sopenharmony_ci h->req_sz = cpu_to_le16(hba->rq_size); 106462306a36Sopenharmony_ci h->req_cnt = cpu_to_le16(hba->rq_count+1); 106562306a36Sopenharmony_ci h->status_sz = cpu_to_le16(sizeof(struct status_msg)); 106662306a36Sopenharmony_ci h->status_cnt = cpu_to_le16(hba->sts_count+1); 106762306a36Sopenharmony_ci h->hosttime = cpu_to_le64(ktime_get_real_seconds()); 106862306a36Sopenharmony_ci h->partner_type = HMU_PARTNER_TYPE; 106962306a36Sopenharmony_ci if (hba->extra_offset) { 107062306a36Sopenharmony_ci h->extra_offset = cpu_to_le32(hba->extra_offset); 107162306a36Sopenharmony_ci h->extra_size = cpu_to_le32(hba->dma_size - hba->extra_offset); 107262306a36Sopenharmony_ci } else 107362306a36Sopenharmony_ci h->extra_offset = h->extra_size = 0; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci status_phys = hba->dma_handle + (hba->rq_count+1) * hba->rq_size; 107662306a36Sopenharmony_ci writel(status_phys, base + IMR0); 107762306a36Sopenharmony_ci readl(base + IMR0); 107862306a36Sopenharmony_ci writel((status_phys >> 16) >> 16, base + IMR1); 107962306a36Sopenharmony_ci readl(base + IMR1); 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci writel((status_phys >> 16) >> 16, base + OMR0); /* old fw compatible */ 108262306a36Sopenharmony_ci readl(base + OMR0); 108362306a36Sopenharmony_ci writel(MU_INBOUND_DOORBELL_HANDSHAKE, base + IDBL); 108462306a36Sopenharmony_ci readl(base + IDBL); /* flush */ 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci udelay(10); 108762306a36Sopenharmony_ci before = jiffies; 108862306a36Sopenharmony_ci while (readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE) { 108962306a36Sopenharmony_ci if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) { 109062306a36Sopenharmony_ci printk(KERN_ERR DRV_NAME 109162306a36Sopenharmony_ci "(%s): no signature after handshake frame\n", 109262306a36Sopenharmony_ci pci_name(hba->pdev)); 109362306a36Sopenharmony_ci return -1; 109462306a36Sopenharmony_ci } 109562306a36Sopenharmony_ci rmb(); 109662306a36Sopenharmony_ci msleep(1); 109762306a36Sopenharmony_ci } 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci writel(0, base + IMR0); 110062306a36Sopenharmony_ci readl(base + IMR0); 110162306a36Sopenharmony_ci writel(0, base + OMR0); 110262306a36Sopenharmony_ci readl(base + OMR0); 110362306a36Sopenharmony_ci writel(0, base + IMR1); 110462306a36Sopenharmony_ci readl(base + IMR1); 110562306a36Sopenharmony_ci writel(0, base + OMR1); 110662306a36Sopenharmony_ci readl(base + OMR1); /* flush */ 110762306a36Sopenharmony_ci return 0; 110862306a36Sopenharmony_ci} 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_cistatic int stex_ss_handshake(struct st_hba *hba) 111162306a36Sopenharmony_ci{ 111262306a36Sopenharmony_ci void __iomem *base = hba->mmio_base; 111362306a36Sopenharmony_ci struct st_msg_header *msg_h; 111462306a36Sopenharmony_ci struct handshake_frame *h; 111562306a36Sopenharmony_ci __le32 *scratch; 111662306a36Sopenharmony_ci u32 data, scratch_size, mailboxdata, operationaldata; 111762306a36Sopenharmony_ci unsigned long before; 111862306a36Sopenharmony_ci int ret = 0; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci before = jiffies; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci if (hba->cardtype == st_yel) { 112362306a36Sopenharmony_ci operationaldata = readl(base + YIOA_STATUS); 112462306a36Sopenharmony_ci while (operationaldata != SS_MU_OPERATIONAL) { 112562306a36Sopenharmony_ci if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) { 112662306a36Sopenharmony_ci printk(KERN_ERR DRV_NAME 112762306a36Sopenharmony_ci "(%s): firmware not operational\n", 112862306a36Sopenharmony_ci pci_name(hba->pdev)); 112962306a36Sopenharmony_ci return -1; 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci msleep(1); 113262306a36Sopenharmony_ci operationaldata = readl(base + YIOA_STATUS); 113362306a36Sopenharmony_ci } 113462306a36Sopenharmony_ci } else { 113562306a36Sopenharmony_ci operationaldata = readl(base + PSCRATCH3); 113662306a36Sopenharmony_ci while (operationaldata != SS_MU_OPERATIONAL) { 113762306a36Sopenharmony_ci if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) { 113862306a36Sopenharmony_ci printk(KERN_ERR DRV_NAME 113962306a36Sopenharmony_ci "(%s): firmware not operational\n", 114062306a36Sopenharmony_ci pci_name(hba->pdev)); 114162306a36Sopenharmony_ci return -1; 114262306a36Sopenharmony_ci } 114362306a36Sopenharmony_ci msleep(1); 114462306a36Sopenharmony_ci operationaldata = readl(base + PSCRATCH3); 114562306a36Sopenharmony_ci } 114662306a36Sopenharmony_ci } 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci msg_h = (struct st_msg_header *)hba->dma_mem; 114962306a36Sopenharmony_ci msg_h->handle = cpu_to_le64(hba->dma_handle); 115062306a36Sopenharmony_ci msg_h->flag = SS_HEAD_HANDSHAKE; 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci h = (struct handshake_frame *)(msg_h + 1); 115362306a36Sopenharmony_ci h->rb_phy = cpu_to_le64(hba->dma_handle); 115462306a36Sopenharmony_ci h->req_sz = cpu_to_le16(hba->rq_size); 115562306a36Sopenharmony_ci h->req_cnt = cpu_to_le16(hba->rq_count+1); 115662306a36Sopenharmony_ci h->status_sz = cpu_to_le16(sizeof(struct status_msg)); 115762306a36Sopenharmony_ci h->status_cnt = cpu_to_le16(hba->sts_count+1); 115862306a36Sopenharmony_ci h->hosttime = cpu_to_le64(ktime_get_real_seconds()); 115962306a36Sopenharmony_ci h->partner_type = HMU_PARTNER_TYPE; 116062306a36Sopenharmony_ci h->extra_offset = h->extra_size = 0; 116162306a36Sopenharmony_ci scratch_size = (hba->sts_count+1)*sizeof(u32); 116262306a36Sopenharmony_ci h->scratch_size = cpu_to_le32(scratch_size); 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci if (hba->cardtype == st_yel) { 116562306a36Sopenharmony_ci data = readl(base + YINT_EN); 116662306a36Sopenharmony_ci data &= ~4; 116762306a36Sopenharmony_ci writel(data, base + YINT_EN); 116862306a36Sopenharmony_ci writel((hba->dma_handle >> 16) >> 16, base + YH2I_REQ_HI); 116962306a36Sopenharmony_ci readl(base + YH2I_REQ_HI); 117062306a36Sopenharmony_ci writel(hba->dma_handle, base + YH2I_REQ); 117162306a36Sopenharmony_ci readl(base + YH2I_REQ); /* flush */ 117262306a36Sopenharmony_ci } else { 117362306a36Sopenharmony_ci data = readl(base + YINT_EN); 117462306a36Sopenharmony_ci data &= ~(1 << 0); 117562306a36Sopenharmony_ci data &= ~(1 << 2); 117662306a36Sopenharmony_ci writel(data, base + YINT_EN); 117762306a36Sopenharmony_ci if (hba->msi_lock == 0) { 117862306a36Sopenharmony_ci /* P3 MSI Register cannot access twice */ 117962306a36Sopenharmony_ci writel((1 << 6), base + YH2I_INT); 118062306a36Sopenharmony_ci hba->msi_lock = 1; 118162306a36Sopenharmony_ci } 118262306a36Sopenharmony_ci writel((hba->dma_handle >> 16) >> 16, base + YH2I_REQ_HI); 118362306a36Sopenharmony_ci writel(hba->dma_handle, base + YH2I_REQ); 118462306a36Sopenharmony_ci } 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci before = jiffies; 118762306a36Sopenharmony_ci scratch = hba->scratch; 118862306a36Sopenharmony_ci if (hba->cardtype == st_yel) { 118962306a36Sopenharmony_ci while (!(le32_to_cpu(*scratch) & SS_STS_HANDSHAKE)) { 119062306a36Sopenharmony_ci if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) { 119162306a36Sopenharmony_ci printk(KERN_ERR DRV_NAME 119262306a36Sopenharmony_ci "(%s): no signature after handshake frame\n", 119362306a36Sopenharmony_ci pci_name(hba->pdev)); 119462306a36Sopenharmony_ci ret = -1; 119562306a36Sopenharmony_ci break; 119662306a36Sopenharmony_ci } 119762306a36Sopenharmony_ci rmb(); 119862306a36Sopenharmony_ci msleep(1); 119962306a36Sopenharmony_ci } 120062306a36Sopenharmony_ci } else { 120162306a36Sopenharmony_ci mailboxdata = readl(base + MAILBOX_BASE + MAILBOX_HNDSHK_STS); 120262306a36Sopenharmony_ci while (mailboxdata != SS_STS_HANDSHAKE) { 120362306a36Sopenharmony_ci if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) { 120462306a36Sopenharmony_ci printk(KERN_ERR DRV_NAME 120562306a36Sopenharmony_ci "(%s): no signature after handshake frame\n", 120662306a36Sopenharmony_ci pci_name(hba->pdev)); 120762306a36Sopenharmony_ci ret = -1; 120862306a36Sopenharmony_ci break; 120962306a36Sopenharmony_ci } 121062306a36Sopenharmony_ci rmb(); 121162306a36Sopenharmony_ci msleep(1); 121262306a36Sopenharmony_ci mailboxdata = readl(base + MAILBOX_BASE + MAILBOX_HNDSHK_STS); 121362306a36Sopenharmony_ci } 121462306a36Sopenharmony_ci } 121562306a36Sopenharmony_ci memset(scratch, 0, scratch_size); 121662306a36Sopenharmony_ci msg_h->flag = 0; 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci return ret; 121962306a36Sopenharmony_ci} 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_cistatic int stex_handshake(struct st_hba *hba) 122262306a36Sopenharmony_ci{ 122362306a36Sopenharmony_ci int err; 122462306a36Sopenharmony_ci unsigned long flags; 122562306a36Sopenharmony_ci unsigned int mu_status; 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci if (hba->cardtype == st_yel || hba->cardtype == st_P3) 122862306a36Sopenharmony_ci err = stex_ss_handshake(hba); 122962306a36Sopenharmony_ci else 123062306a36Sopenharmony_ci err = stex_common_handshake(hba); 123162306a36Sopenharmony_ci spin_lock_irqsave(hba->host->host_lock, flags); 123262306a36Sopenharmony_ci mu_status = hba->mu_status; 123362306a36Sopenharmony_ci if (err == 0) { 123462306a36Sopenharmony_ci hba->req_head = 0; 123562306a36Sopenharmony_ci hba->req_tail = 0; 123662306a36Sopenharmony_ci hba->status_head = 0; 123762306a36Sopenharmony_ci hba->status_tail = 0; 123862306a36Sopenharmony_ci hba->out_req_cnt = 0; 123962306a36Sopenharmony_ci hba->mu_status = MU_STATE_STARTED; 124062306a36Sopenharmony_ci } else 124162306a36Sopenharmony_ci hba->mu_status = MU_STATE_FAILED; 124262306a36Sopenharmony_ci if (mu_status == MU_STATE_RESETTING) 124362306a36Sopenharmony_ci wake_up_all(&hba->reset_waitq); 124462306a36Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 124562306a36Sopenharmony_ci return err; 124662306a36Sopenharmony_ci} 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_cistatic int stex_abort(struct scsi_cmnd *cmd) 124962306a36Sopenharmony_ci{ 125062306a36Sopenharmony_ci struct Scsi_Host *host = cmd->device->host; 125162306a36Sopenharmony_ci struct st_hba *hba = (struct st_hba *)host->hostdata; 125262306a36Sopenharmony_ci u16 tag = scsi_cmd_to_rq(cmd)->tag; 125362306a36Sopenharmony_ci void __iomem *base; 125462306a36Sopenharmony_ci u32 data; 125562306a36Sopenharmony_ci int result = SUCCESS; 125662306a36Sopenharmony_ci unsigned long flags; 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci scmd_printk(KERN_INFO, cmd, "aborting command\n"); 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci base = hba->mmio_base; 126162306a36Sopenharmony_ci spin_lock_irqsave(host->host_lock, flags); 126262306a36Sopenharmony_ci if (tag < host->can_queue && 126362306a36Sopenharmony_ci hba->ccb[tag].req && hba->ccb[tag].cmd == cmd) 126462306a36Sopenharmony_ci hba->wait_ccb = &hba->ccb[tag]; 126562306a36Sopenharmony_ci else 126662306a36Sopenharmony_ci goto out; 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci if (hba->cardtype == st_yel) { 126962306a36Sopenharmony_ci data = readl(base + YI2H_INT); 127062306a36Sopenharmony_ci if (data == 0 || data == 0xffffffff) 127162306a36Sopenharmony_ci goto fail_out; 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci writel(data, base + YI2H_INT_C); 127462306a36Sopenharmony_ci stex_ss_mu_intr(hba); 127562306a36Sopenharmony_ci } else if (hba->cardtype == st_P3) { 127662306a36Sopenharmony_ci data = readl(base + PSCRATCH4); 127762306a36Sopenharmony_ci if (data == 0xffffffff) 127862306a36Sopenharmony_ci goto fail_out; 127962306a36Sopenharmony_ci if (data != 0) { 128062306a36Sopenharmony_ci writel(data, base + PSCRATCH1); 128162306a36Sopenharmony_ci writel((1 << 22), base + YH2I_INT); 128262306a36Sopenharmony_ci } 128362306a36Sopenharmony_ci stex_ss_mu_intr(hba); 128462306a36Sopenharmony_ci } else { 128562306a36Sopenharmony_ci data = readl(base + ODBL); 128662306a36Sopenharmony_ci if (data == 0 || data == 0xffffffff) 128762306a36Sopenharmony_ci goto fail_out; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci writel(data, base + ODBL); 129062306a36Sopenharmony_ci readl(base + ODBL); /* flush */ 129162306a36Sopenharmony_ci stex_mu_intr(hba, data); 129262306a36Sopenharmony_ci } 129362306a36Sopenharmony_ci if (hba->wait_ccb == NULL) { 129462306a36Sopenharmony_ci printk(KERN_WARNING DRV_NAME 129562306a36Sopenharmony_ci "(%s): lost interrupt\n", pci_name(hba->pdev)); 129662306a36Sopenharmony_ci goto out; 129762306a36Sopenharmony_ci } 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_cifail_out: 130062306a36Sopenharmony_ci scsi_dma_unmap(cmd); 130162306a36Sopenharmony_ci hba->wait_ccb->req = NULL; /* nullify the req's future return */ 130262306a36Sopenharmony_ci hba->wait_ccb = NULL; 130362306a36Sopenharmony_ci result = FAILED; 130462306a36Sopenharmony_ciout: 130562306a36Sopenharmony_ci spin_unlock_irqrestore(host->host_lock, flags); 130662306a36Sopenharmony_ci return result; 130762306a36Sopenharmony_ci} 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_cistatic void stex_hard_reset(struct st_hba *hba) 131062306a36Sopenharmony_ci{ 131162306a36Sopenharmony_ci struct pci_bus *bus; 131262306a36Sopenharmony_ci int i; 131362306a36Sopenharmony_ci u16 pci_cmd; 131462306a36Sopenharmony_ci u8 pci_bctl; 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci for (i = 0; i < 16; i++) 131762306a36Sopenharmony_ci pci_read_config_dword(hba->pdev, i * 4, 131862306a36Sopenharmony_ci &hba->pdev->saved_config_space[i]); 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci /* Reset secondary bus. Our controller(MU/ATU) is the only device on 132162306a36Sopenharmony_ci secondary bus. Consult Intel 80331/3 developer's manual for detail */ 132262306a36Sopenharmony_ci bus = hba->pdev->bus; 132362306a36Sopenharmony_ci pci_read_config_byte(bus->self, PCI_BRIDGE_CONTROL, &pci_bctl); 132462306a36Sopenharmony_ci pci_bctl |= PCI_BRIDGE_CTL_BUS_RESET; 132562306a36Sopenharmony_ci pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, pci_bctl); 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci /* 132862306a36Sopenharmony_ci * 1 ms may be enough for 8-port controllers. But 16-port controllers 132962306a36Sopenharmony_ci * require more time to finish bus reset. Use 100 ms here for safety 133062306a36Sopenharmony_ci */ 133162306a36Sopenharmony_ci msleep(100); 133262306a36Sopenharmony_ci pci_bctl &= ~PCI_BRIDGE_CTL_BUS_RESET; 133362306a36Sopenharmony_ci pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, pci_bctl); 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci for (i = 0; i < MU_HARD_RESET_WAIT; i++) { 133662306a36Sopenharmony_ci pci_read_config_word(hba->pdev, PCI_COMMAND, &pci_cmd); 133762306a36Sopenharmony_ci if (pci_cmd != 0xffff && (pci_cmd & PCI_COMMAND_MASTER)) 133862306a36Sopenharmony_ci break; 133962306a36Sopenharmony_ci msleep(1); 134062306a36Sopenharmony_ci } 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci ssleep(5); 134362306a36Sopenharmony_ci for (i = 0; i < 16; i++) 134462306a36Sopenharmony_ci pci_write_config_dword(hba->pdev, i * 4, 134562306a36Sopenharmony_ci hba->pdev->saved_config_space[i]); 134662306a36Sopenharmony_ci} 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_cistatic int stex_yos_reset(struct st_hba *hba) 134962306a36Sopenharmony_ci{ 135062306a36Sopenharmony_ci void __iomem *base; 135162306a36Sopenharmony_ci unsigned long flags, before; 135262306a36Sopenharmony_ci int ret = 0; 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci base = hba->mmio_base; 135562306a36Sopenharmony_ci writel(MU_INBOUND_DOORBELL_RESET, base + IDBL); 135662306a36Sopenharmony_ci readl(base + IDBL); /* flush */ 135762306a36Sopenharmony_ci before = jiffies; 135862306a36Sopenharmony_ci while (hba->out_req_cnt > 0) { 135962306a36Sopenharmony_ci if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) { 136062306a36Sopenharmony_ci printk(KERN_WARNING DRV_NAME 136162306a36Sopenharmony_ci "(%s): reset timeout\n", pci_name(hba->pdev)); 136262306a36Sopenharmony_ci ret = -1; 136362306a36Sopenharmony_ci break; 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci msleep(1); 136662306a36Sopenharmony_ci } 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci spin_lock_irqsave(hba->host->host_lock, flags); 136962306a36Sopenharmony_ci if (ret == -1) 137062306a36Sopenharmony_ci hba->mu_status = MU_STATE_FAILED; 137162306a36Sopenharmony_ci else 137262306a36Sopenharmony_ci hba->mu_status = MU_STATE_STARTED; 137362306a36Sopenharmony_ci wake_up_all(&hba->reset_waitq); 137462306a36Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci return ret; 137762306a36Sopenharmony_ci} 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_cistatic void stex_ss_reset(struct st_hba *hba) 138062306a36Sopenharmony_ci{ 138162306a36Sopenharmony_ci writel(SS_H2I_INT_RESET, hba->mmio_base + YH2I_INT); 138262306a36Sopenharmony_ci readl(hba->mmio_base + YH2I_INT); 138362306a36Sopenharmony_ci ssleep(5); 138462306a36Sopenharmony_ci} 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_cistatic void stex_p3_reset(struct st_hba *hba) 138762306a36Sopenharmony_ci{ 138862306a36Sopenharmony_ci writel(SS_H2I_INT_RESET, hba->mmio_base + YH2I_INT); 138962306a36Sopenharmony_ci ssleep(5); 139062306a36Sopenharmony_ci} 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_cistatic int stex_do_reset(struct st_hba *hba) 139362306a36Sopenharmony_ci{ 139462306a36Sopenharmony_ci unsigned long flags; 139562306a36Sopenharmony_ci unsigned int mu_status = MU_STATE_RESETTING; 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci spin_lock_irqsave(hba->host->host_lock, flags); 139862306a36Sopenharmony_ci if (hba->mu_status == MU_STATE_STARTING) { 139962306a36Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 140062306a36Sopenharmony_ci printk(KERN_INFO DRV_NAME "(%s): request reset during init\n", 140162306a36Sopenharmony_ci pci_name(hba->pdev)); 140262306a36Sopenharmony_ci return 0; 140362306a36Sopenharmony_ci } 140462306a36Sopenharmony_ci while (hba->mu_status == MU_STATE_RESETTING) { 140562306a36Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 140662306a36Sopenharmony_ci wait_event_timeout(hba->reset_waitq, 140762306a36Sopenharmony_ci hba->mu_status != MU_STATE_RESETTING, 140862306a36Sopenharmony_ci MU_MAX_DELAY * HZ); 140962306a36Sopenharmony_ci spin_lock_irqsave(hba->host->host_lock, flags); 141062306a36Sopenharmony_ci mu_status = hba->mu_status; 141162306a36Sopenharmony_ci } 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci if (mu_status != MU_STATE_RESETTING) { 141462306a36Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 141562306a36Sopenharmony_ci return (mu_status == MU_STATE_STARTED) ? 0 : -1; 141662306a36Sopenharmony_ci } 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci hba->mu_status = MU_STATE_RESETTING; 141962306a36Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci if (hba->cardtype == st_yosemite) 142262306a36Sopenharmony_ci return stex_yos_reset(hba); 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci if (hba->cardtype == st_shasta) 142562306a36Sopenharmony_ci stex_hard_reset(hba); 142662306a36Sopenharmony_ci else if (hba->cardtype == st_yel) 142762306a36Sopenharmony_ci stex_ss_reset(hba); 142862306a36Sopenharmony_ci else if (hba->cardtype == st_P3) 142962306a36Sopenharmony_ci stex_p3_reset(hba); 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci return_abnormal_state(hba, DID_RESET); 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci if (stex_handshake(hba) == 0) 143462306a36Sopenharmony_ci return 0; 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci printk(KERN_WARNING DRV_NAME "(%s): resetting: handshake failed\n", 143762306a36Sopenharmony_ci pci_name(hba->pdev)); 143862306a36Sopenharmony_ci return -1; 143962306a36Sopenharmony_ci} 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_cistatic int stex_reset(struct scsi_cmnd *cmd) 144262306a36Sopenharmony_ci{ 144362306a36Sopenharmony_ci struct st_hba *hba; 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci hba = (struct st_hba *) &cmd->device->host->hostdata[0]; 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci shost_printk(KERN_INFO, cmd->device->host, 144862306a36Sopenharmony_ci "resetting host\n"); 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci return stex_do_reset(hba) ? FAILED : SUCCESS; 145162306a36Sopenharmony_ci} 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_cistatic void stex_reset_work(struct work_struct *work) 145462306a36Sopenharmony_ci{ 145562306a36Sopenharmony_ci struct st_hba *hba = container_of(work, struct st_hba, reset_work); 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci stex_do_reset(hba); 145862306a36Sopenharmony_ci} 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_cistatic int stex_biosparam(struct scsi_device *sdev, 146162306a36Sopenharmony_ci struct block_device *bdev, sector_t capacity, int geom[]) 146262306a36Sopenharmony_ci{ 146362306a36Sopenharmony_ci int heads = 255, sectors = 63; 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci if (capacity < 0x200000) { 146662306a36Sopenharmony_ci heads = 64; 146762306a36Sopenharmony_ci sectors = 32; 146862306a36Sopenharmony_ci } 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci sector_div(capacity, heads * sectors); 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci geom[0] = heads; 147362306a36Sopenharmony_ci geom[1] = sectors; 147462306a36Sopenharmony_ci geom[2] = capacity; 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci return 0; 147762306a36Sopenharmony_ci} 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_cistatic const struct scsi_host_template driver_template = { 148062306a36Sopenharmony_ci .module = THIS_MODULE, 148162306a36Sopenharmony_ci .name = DRV_NAME, 148262306a36Sopenharmony_ci .proc_name = DRV_NAME, 148362306a36Sopenharmony_ci .bios_param = stex_biosparam, 148462306a36Sopenharmony_ci .queuecommand = stex_queuecommand, 148562306a36Sopenharmony_ci .slave_configure = stex_slave_config, 148662306a36Sopenharmony_ci .eh_abort_handler = stex_abort, 148762306a36Sopenharmony_ci .eh_host_reset_handler = stex_reset, 148862306a36Sopenharmony_ci .this_id = -1, 148962306a36Sopenharmony_ci .dma_boundary = PAGE_SIZE - 1, 149062306a36Sopenharmony_ci}; 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_cistatic struct pci_device_id stex_pci_tbl[] = { 149362306a36Sopenharmony_ci /* st_shasta */ 149462306a36Sopenharmony_ci { 0x105a, 0x8350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 149562306a36Sopenharmony_ci st_shasta }, /* SuperTrak EX8350/8300/16350/16300 */ 149662306a36Sopenharmony_ci { 0x105a, 0xc350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 149762306a36Sopenharmony_ci st_shasta }, /* SuperTrak EX12350 */ 149862306a36Sopenharmony_ci { 0x105a, 0x4302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 149962306a36Sopenharmony_ci st_shasta }, /* SuperTrak EX4350 */ 150062306a36Sopenharmony_ci { 0x105a, 0xe350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 150162306a36Sopenharmony_ci st_shasta }, /* SuperTrak EX24350 */ 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci /* st_vsc */ 150462306a36Sopenharmony_ci { 0x105a, 0x7250, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_vsc }, 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci /* st_yosemite */ 150762306a36Sopenharmony_ci { 0x105a, 0x8650, 0x105a, PCI_ANY_ID, 0, 0, st_yosemite }, 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci /* st_seq */ 151062306a36Sopenharmony_ci { 0x105a, 0x3360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_seq }, 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci /* st_yel */ 151362306a36Sopenharmony_ci { 0x105a, 0x8650, 0x1033, PCI_ANY_ID, 0, 0, st_yel }, 151462306a36Sopenharmony_ci { 0x105a, 0x8760, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_yel }, 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci /* st_P3, pluto */ 151762306a36Sopenharmony_ci { PCI_VENDOR_ID_PROMISE, 0x8870, PCI_VENDOR_ID_PROMISE, 151862306a36Sopenharmony_ci 0x8870, 0, 0, st_P3 }, 151962306a36Sopenharmony_ci /* st_P3, p3 */ 152062306a36Sopenharmony_ci { PCI_VENDOR_ID_PROMISE, 0x8870, PCI_VENDOR_ID_PROMISE, 152162306a36Sopenharmony_ci 0x4300, 0, 0, st_P3 }, 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci /* st_P3, SymplyStor4E */ 152462306a36Sopenharmony_ci { PCI_VENDOR_ID_PROMISE, 0x8871, PCI_VENDOR_ID_PROMISE, 152562306a36Sopenharmony_ci 0x4311, 0, 0, st_P3 }, 152662306a36Sopenharmony_ci /* st_P3, SymplyStor8E */ 152762306a36Sopenharmony_ci { PCI_VENDOR_ID_PROMISE, 0x8871, PCI_VENDOR_ID_PROMISE, 152862306a36Sopenharmony_ci 0x4312, 0, 0, st_P3 }, 152962306a36Sopenharmony_ci /* st_P3, SymplyStor4 */ 153062306a36Sopenharmony_ci { PCI_VENDOR_ID_PROMISE, 0x8871, PCI_VENDOR_ID_PROMISE, 153162306a36Sopenharmony_ci 0x4321, 0, 0, st_P3 }, 153262306a36Sopenharmony_ci /* st_P3, SymplyStor8 */ 153362306a36Sopenharmony_ci { PCI_VENDOR_ID_PROMISE, 0x8871, PCI_VENDOR_ID_PROMISE, 153462306a36Sopenharmony_ci 0x4322, 0, 0, st_P3 }, 153562306a36Sopenharmony_ci { } /* terminate list */ 153662306a36Sopenharmony_ci}; 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_cistatic struct st_card_info stex_card_info[] = { 153962306a36Sopenharmony_ci /* st_shasta */ 154062306a36Sopenharmony_ci { 154162306a36Sopenharmony_ci .max_id = 17, 154262306a36Sopenharmony_ci .max_lun = 8, 154362306a36Sopenharmony_ci .max_channel = 0, 154462306a36Sopenharmony_ci .rq_count = 32, 154562306a36Sopenharmony_ci .rq_size = 1048, 154662306a36Sopenharmony_ci .sts_count = 32, 154762306a36Sopenharmony_ci .alloc_rq = stex_alloc_req, 154862306a36Sopenharmony_ci .map_sg = stex_map_sg, 154962306a36Sopenharmony_ci .send = stex_send_cmd, 155062306a36Sopenharmony_ci }, 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci /* st_vsc */ 155362306a36Sopenharmony_ci { 155462306a36Sopenharmony_ci .max_id = 129, 155562306a36Sopenharmony_ci .max_lun = 1, 155662306a36Sopenharmony_ci .max_channel = 0, 155762306a36Sopenharmony_ci .rq_count = 32, 155862306a36Sopenharmony_ci .rq_size = 1048, 155962306a36Sopenharmony_ci .sts_count = 32, 156062306a36Sopenharmony_ci .alloc_rq = stex_alloc_req, 156162306a36Sopenharmony_ci .map_sg = stex_map_sg, 156262306a36Sopenharmony_ci .send = stex_send_cmd, 156362306a36Sopenharmony_ci }, 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci /* st_yosemite */ 156662306a36Sopenharmony_ci { 156762306a36Sopenharmony_ci .max_id = 2, 156862306a36Sopenharmony_ci .max_lun = 256, 156962306a36Sopenharmony_ci .max_channel = 0, 157062306a36Sopenharmony_ci .rq_count = 256, 157162306a36Sopenharmony_ci .rq_size = 1048, 157262306a36Sopenharmony_ci .sts_count = 256, 157362306a36Sopenharmony_ci .alloc_rq = stex_alloc_req, 157462306a36Sopenharmony_ci .map_sg = stex_map_sg, 157562306a36Sopenharmony_ci .send = stex_send_cmd, 157662306a36Sopenharmony_ci }, 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci /* st_seq */ 157962306a36Sopenharmony_ci { 158062306a36Sopenharmony_ci .max_id = 129, 158162306a36Sopenharmony_ci .max_lun = 1, 158262306a36Sopenharmony_ci .max_channel = 0, 158362306a36Sopenharmony_ci .rq_count = 32, 158462306a36Sopenharmony_ci .rq_size = 1048, 158562306a36Sopenharmony_ci .sts_count = 32, 158662306a36Sopenharmony_ci .alloc_rq = stex_alloc_req, 158762306a36Sopenharmony_ci .map_sg = stex_map_sg, 158862306a36Sopenharmony_ci .send = stex_send_cmd, 158962306a36Sopenharmony_ci }, 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci /* st_yel */ 159262306a36Sopenharmony_ci { 159362306a36Sopenharmony_ci .max_id = 129, 159462306a36Sopenharmony_ci .max_lun = 256, 159562306a36Sopenharmony_ci .max_channel = 3, 159662306a36Sopenharmony_ci .rq_count = 801, 159762306a36Sopenharmony_ci .rq_size = 512, 159862306a36Sopenharmony_ci .sts_count = 801, 159962306a36Sopenharmony_ci .alloc_rq = stex_ss_alloc_req, 160062306a36Sopenharmony_ci .map_sg = stex_ss_map_sg, 160162306a36Sopenharmony_ci .send = stex_ss_send_cmd, 160262306a36Sopenharmony_ci }, 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci /* st_P3 */ 160562306a36Sopenharmony_ci { 160662306a36Sopenharmony_ci .max_id = 129, 160762306a36Sopenharmony_ci .max_lun = 256, 160862306a36Sopenharmony_ci .max_channel = 0, 160962306a36Sopenharmony_ci .rq_count = 801, 161062306a36Sopenharmony_ci .rq_size = 512, 161162306a36Sopenharmony_ci .sts_count = 801, 161262306a36Sopenharmony_ci .alloc_rq = stex_ss_alloc_req, 161362306a36Sopenharmony_ci .map_sg = stex_ss_map_sg, 161462306a36Sopenharmony_ci .send = stex_ss_send_cmd, 161562306a36Sopenharmony_ci }, 161662306a36Sopenharmony_ci}; 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_cistatic int stex_request_irq(struct st_hba *hba) 161962306a36Sopenharmony_ci{ 162062306a36Sopenharmony_ci struct pci_dev *pdev = hba->pdev; 162162306a36Sopenharmony_ci int status; 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci if (msi || hba->cardtype == st_P3) { 162462306a36Sopenharmony_ci status = pci_enable_msi(pdev); 162562306a36Sopenharmony_ci if (status != 0) 162662306a36Sopenharmony_ci printk(KERN_ERR DRV_NAME 162762306a36Sopenharmony_ci "(%s): error %d setting up MSI\n", 162862306a36Sopenharmony_ci pci_name(pdev), status); 162962306a36Sopenharmony_ci else 163062306a36Sopenharmony_ci hba->msi_enabled = 1; 163162306a36Sopenharmony_ci } else 163262306a36Sopenharmony_ci hba->msi_enabled = 0; 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci status = request_irq(pdev->irq, 163562306a36Sopenharmony_ci (hba->cardtype == st_yel || hba->cardtype == st_P3) ? 163662306a36Sopenharmony_ci stex_ss_intr : stex_intr, IRQF_SHARED, DRV_NAME, hba); 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci if (status != 0) { 163962306a36Sopenharmony_ci if (hba->msi_enabled) 164062306a36Sopenharmony_ci pci_disable_msi(pdev); 164162306a36Sopenharmony_ci } 164262306a36Sopenharmony_ci return status; 164362306a36Sopenharmony_ci} 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_cistatic void stex_free_irq(struct st_hba *hba) 164662306a36Sopenharmony_ci{ 164762306a36Sopenharmony_ci struct pci_dev *pdev = hba->pdev; 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci free_irq(pdev->irq, hba); 165062306a36Sopenharmony_ci if (hba->msi_enabled) 165162306a36Sopenharmony_ci pci_disable_msi(pdev); 165262306a36Sopenharmony_ci} 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_cistatic int stex_probe(struct pci_dev *pdev, const struct pci_device_id *id) 165562306a36Sopenharmony_ci{ 165662306a36Sopenharmony_ci struct st_hba *hba; 165762306a36Sopenharmony_ci struct Scsi_Host *host; 165862306a36Sopenharmony_ci const struct st_card_info *ci = NULL; 165962306a36Sopenharmony_ci u32 sts_offset, cp_offset, scratch_offset; 166062306a36Sopenharmony_ci int err; 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci err = pci_enable_device(pdev); 166362306a36Sopenharmony_ci if (err) 166462306a36Sopenharmony_ci return err; 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci pci_set_master(pdev); 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci S6flag = 0; 166962306a36Sopenharmony_ci register_reboot_notifier(&stex_notifier); 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci host = scsi_host_alloc(&driver_template, sizeof(struct st_hba)); 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci if (!host) { 167462306a36Sopenharmony_ci printk(KERN_ERR DRV_NAME "(%s): scsi_host_alloc failed\n", 167562306a36Sopenharmony_ci pci_name(pdev)); 167662306a36Sopenharmony_ci err = -ENOMEM; 167762306a36Sopenharmony_ci goto out_disable; 167862306a36Sopenharmony_ci } 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci hba = (struct st_hba *)host->hostdata; 168162306a36Sopenharmony_ci memset(hba, 0, sizeof(struct st_hba)); 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci err = pci_request_regions(pdev, DRV_NAME); 168462306a36Sopenharmony_ci if (err < 0) { 168562306a36Sopenharmony_ci printk(KERN_ERR DRV_NAME "(%s): request regions failed\n", 168662306a36Sopenharmony_ci pci_name(pdev)); 168762306a36Sopenharmony_ci goto out_scsi_host_put; 168862306a36Sopenharmony_ci } 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci hba->mmio_base = pci_ioremap_bar(pdev, 0); 169162306a36Sopenharmony_ci if ( !hba->mmio_base) { 169262306a36Sopenharmony_ci printk(KERN_ERR DRV_NAME "(%s): memory map failed\n", 169362306a36Sopenharmony_ci pci_name(pdev)); 169462306a36Sopenharmony_ci err = -ENOMEM; 169562306a36Sopenharmony_ci goto out_release_regions; 169662306a36Sopenharmony_ci } 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 169962306a36Sopenharmony_ci if (err) 170062306a36Sopenharmony_ci err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 170162306a36Sopenharmony_ci if (err) { 170262306a36Sopenharmony_ci printk(KERN_ERR DRV_NAME "(%s): set dma mask failed\n", 170362306a36Sopenharmony_ci pci_name(pdev)); 170462306a36Sopenharmony_ci goto out_iounmap; 170562306a36Sopenharmony_ci } 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci hba->cardtype = (unsigned int) id->driver_data; 170862306a36Sopenharmony_ci ci = &stex_card_info[hba->cardtype]; 170962306a36Sopenharmony_ci switch (id->subdevice) { 171062306a36Sopenharmony_ci case 0x4221: 171162306a36Sopenharmony_ci case 0x4222: 171262306a36Sopenharmony_ci case 0x4223: 171362306a36Sopenharmony_ci case 0x4224: 171462306a36Sopenharmony_ci case 0x4225: 171562306a36Sopenharmony_ci case 0x4226: 171662306a36Sopenharmony_ci case 0x4227: 171762306a36Sopenharmony_ci case 0x4261: 171862306a36Sopenharmony_ci case 0x4262: 171962306a36Sopenharmony_ci case 0x4263: 172062306a36Sopenharmony_ci case 0x4264: 172162306a36Sopenharmony_ci case 0x4265: 172262306a36Sopenharmony_ci break; 172362306a36Sopenharmony_ci default: 172462306a36Sopenharmony_ci if (hba->cardtype == st_yel || hba->cardtype == st_P3) 172562306a36Sopenharmony_ci hba->supports_pm = 1; 172662306a36Sopenharmony_ci } 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci sts_offset = scratch_offset = (ci->rq_count+1) * ci->rq_size; 172962306a36Sopenharmony_ci if (hba->cardtype == st_yel || hba->cardtype == st_P3) 173062306a36Sopenharmony_ci sts_offset += (ci->sts_count+1) * sizeof(u32); 173162306a36Sopenharmony_ci cp_offset = sts_offset + (ci->sts_count+1) * sizeof(struct status_msg); 173262306a36Sopenharmony_ci hba->dma_size = cp_offset + sizeof(struct st_frame); 173362306a36Sopenharmony_ci if (hba->cardtype == st_seq || 173462306a36Sopenharmony_ci (hba->cardtype == st_vsc && (pdev->subsystem_device & 1))) { 173562306a36Sopenharmony_ci hba->extra_offset = hba->dma_size; 173662306a36Sopenharmony_ci hba->dma_size += ST_ADDITIONAL_MEM; 173762306a36Sopenharmony_ci } 173862306a36Sopenharmony_ci hba->dma_mem = dma_alloc_coherent(&pdev->dev, 173962306a36Sopenharmony_ci hba->dma_size, &hba->dma_handle, GFP_KERNEL); 174062306a36Sopenharmony_ci if (!hba->dma_mem) { 174162306a36Sopenharmony_ci /* Retry minimum coherent mapping for st_seq and st_vsc */ 174262306a36Sopenharmony_ci if (hba->cardtype == st_seq || 174362306a36Sopenharmony_ci (hba->cardtype == st_vsc && (pdev->subsystem_device & 1))) { 174462306a36Sopenharmony_ci printk(KERN_WARNING DRV_NAME 174562306a36Sopenharmony_ci "(%s): allocating min buffer for controller\n", 174662306a36Sopenharmony_ci pci_name(pdev)); 174762306a36Sopenharmony_ci hba->dma_size = hba->extra_offset 174862306a36Sopenharmony_ci + ST_ADDITIONAL_MEM_MIN; 174962306a36Sopenharmony_ci hba->dma_mem = dma_alloc_coherent(&pdev->dev, 175062306a36Sopenharmony_ci hba->dma_size, &hba->dma_handle, GFP_KERNEL); 175162306a36Sopenharmony_ci } 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci if (!hba->dma_mem) { 175462306a36Sopenharmony_ci err = -ENOMEM; 175562306a36Sopenharmony_ci printk(KERN_ERR DRV_NAME "(%s): dma mem alloc failed\n", 175662306a36Sopenharmony_ci pci_name(pdev)); 175762306a36Sopenharmony_ci goto out_iounmap; 175862306a36Sopenharmony_ci } 175962306a36Sopenharmony_ci } 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci hba->ccb = kcalloc(ci->rq_count, sizeof(struct st_ccb), GFP_KERNEL); 176262306a36Sopenharmony_ci if (!hba->ccb) { 176362306a36Sopenharmony_ci err = -ENOMEM; 176462306a36Sopenharmony_ci printk(KERN_ERR DRV_NAME "(%s): ccb alloc failed\n", 176562306a36Sopenharmony_ci pci_name(pdev)); 176662306a36Sopenharmony_ci goto out_pci_free; 176762306a36Sopenharmony_ci } 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ci if (hba->cardtype == st_yel || hba->cardtype == st_P3) 177062306a36Sopenharmony_ci hba->scratch = (__le32 *)(hba->dma_mem + scratch_offset); 177162306a36Sopenharmony_ci hba->status_buffer = (struct status_msg *)(hba->dma_mem + sts_offset); 177262306a36Sopenharmony_ci hba->copy_buffer = hba->dma_mem + cp_offset; 177362306a36Sopenharmony_ci hba->rq_count = ci->rq_count; 177462306a36Sopenharmony_ci hba->rq_size = ci->rq_size; 177562306a36Sopenharmony_ci hba->sts_count = ci->sts_count; 177662306a36Sopenharmony_ci hba->alloc_rq = ci->alloc_rq; 177762306a36Sopenharmony_ci hba->map_sg = ci->map_sg; 177862306a36Sopenharmony_ci hba->send = ci->send; 177962306a36Sopenharmony_ci hba->mu_status = MU_STATE_STARTING; 178062306a36Sopenharmony_ci hba->msi_lock = 0; 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci if (hba->cardtype == st_yel || hba->cardtype == st_P3) 178362306a36Sopenharmony_ci host->sg_tablesize = 38; 178462306a36Sopenharmony_ci else 178562306a36Sopenharmony_ci host->sg_tablesize = 32; 178662306a36Sopenharmony_ci host->can_queue = ci->rq_count; 178762306a36Sopenharmony_ci host->cmd_per_lun = ci->rq_count; 178862306a36Sopenharmony_ci host->max_id = ci->max_id; 178962306a36Sopenharmony_ci host->max_lun = ci->max_lun; 179062306a36Sopenharmony_ci host->max_channel = ci->max_channel; 179162306a36Sopenharmony_ci host->unique_id = host->host_no; 179262306a36Sopenharmony_ci host->max_cmd_len = STEX_CDB_LENGTH; 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci hba->host = host; 179562306a36Sopenharmony_ci hba->pdev = pdev; 179662306a36Sopenharmony_ci init_waitqueue_head(&hba->reset_waitq); 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci snprintf(hba->work_q_name, sizeof(hba->work_q_name), 179962306a36Sopenharmony_ci "stex_wq_%d", host->host_no); 180062306a36Sopenharmony_ci hba->work_q = create_singlethread_workqueue(hba->work_q_name); 180162306a36Sopenharmony_ci if (!hba->work_q) { 180262306a36Sopenharmony_ci printk(KERN_ERR DRV_NAME "(%s): create workqueue failed\n", 180362306a36Sopenharmony_ci pci_name(pdev)); 180462306a36Sopenharmony_ci err = -ENOMEM; 180562306a36Sopenharmony_ci goto out_ccb_free; 180662306a36Sopenharmony_ci } 180762306a36Sopenharmony_ci INIT_WORK(&hba->reset_work, stex_reset_work); 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci err = stex_request_irq(hba); 181062306a36Sopenharmony_ci if (err) { 181162306a36Sopenharmony_ci printk(KERN_ERR DRV_NAME "(%s): request irq failed\n", 181262306a36Sopenharmony_ci pci_name(pdev)); 181362306a36Sopenharmony_ci goto out_free_wq; 181462306a36Sopenharmony_ci } 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci err = stex_handshake(hba); 181762306a36Sopenharmony_ci if (err) 181862306a36Sopenharmony_ci goto out_free_irq; 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci pci_set_drvdata(pdev, hba); 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci err = scsi_add_host(host, &pdev->dev); 182362306a36Sopenharmony_ci if (err) { 182462306a36Sopenharmony_ci printk(KERN_ERR DRV_NAME "(%s): scsi_add_host failed\n", 182562306a36Sopenharmony_ci pci_name(pdev)); 182662306a36Sopenharmony_ci goto out_free_irq; 182762306a36Sopenharmony_ci } 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_ci scsi_scan_host(host); 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci return 0; 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ciout_free_irq: 183462306a36Sopenharmony_ci stex_free_irq(hba); 183562306a36Sopenharmony_ciout_free_wq: 183662306a36Sopenharmony_ci destroy_workqueue(hba->work_q); 183762306a36Sopenharmony_ciout_ccb_free: 183862306a36Sopenharmony_ci kfree(hba->ccb); 183962306a36Sopenharmony_ciout_pci_free: 184062306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, hba->dma_size, 184162306a36Sopenharmony_ci hba->dma_mem, hba->dma_handle); 184262306a36Sopenharmony_ciout_iounmap: 184362306a36Sopenharmony_ci iounmap(hba->mmio_base); 184462306a36Sopenharmony_ciout_release_regions: 184562306a36Sopenharmony_ci pci_release_regions(pdev); 184662306a36Sopenharmony_ciout_scsi_host_put: 184762306a36Sopenharmony_ci scsi_host_put(host); 184862306a36Sopenharmony_ciout_disable: 184962306a36Sopenharmony_ci pci_disable_device(pdev); 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci return err; 185262306a36Sopenharmony_ci} 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_cistatic void stex_hba_stop(struct st_hba *hba, int st_sleep_mic) 185562306a36Sopenharmony_ci{ 185662306a36Sopenharmony_ci struct req_msg *req; 185762306a36Sopenharmony_ci struct st_msg_header *msg_h; 185862306a36Sopenharmony_ci unsigned long flags; 185962306a36Sopenharmony_ci unsigned long before; 186062306a36Sopenharmony_ci u16 tag = 0; 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci spin_lock_irqsave(hba->host->host_lock, flags); 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci if ((hba->cardtype == st_yel || hba->cardtype == st_P3) && 186562306a36Sopenharmony_ci hba->supports_pm == 1) { 186662306a36Sopenharmony_ci if (st_sleep_mic == ST_NOTHANDLED) { 186762306a36Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 186862306a36Sopenharmony_ci return; 186962306a36Sopenharmony_ci } 187062306a36Sopenharmony_ci } 187162306a36Sopenharmony_ci req = hba->alloc_rq(hba); 187262306a36Sopenharmony_ci if (hba->cardtype == st_yel || hba->cardtype == st_P3) { 187362306a36Sopenharmony_ci msg_h = (struct st_msg_header *)req - 1; 187462306a36Sopenharmony_ci memset(msg_h, 0, hba->rq_size); 187562306a36Sopenharmony_ci } else 187662306a36Sopenharmony_ci memset(req, 0, hba->rq_size); 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci if ((hba->cardtype == st_yosemite || hba->cardtype == st_yel 187962306a36Sopenharmony_ci || hba->cardtype == st_P3) 188062306a36Sopenharmony_ci && st_sleep_mic == ST_IGNORED) { 188162306a36Sopenharmony_ci req->cdb[0] = MGT_CMD; 188262306a36Sopenharmony_ci req->cdb[1] = MGT_CMD_SIGNATURE; 188362306a36Sopenharmony_ci req->cdb[2] = CTLR_CONFIG_CMD; 188462306a36Sopenharmony_ci req->cdb[3] = CTLR_SHUTDOWN; 188562306a36Sopenharmony_ci } else if ((hba->cardtype == st_yel || hba->cardtype == st_P3) 188662306a36Sopenharmony_ci && st_sleep_mic != ST_IGNORED) { 188762306a36Sopenharmony_ci req->cdb[0] = MGT_CMD; 188862306a36Sopenharmony_ci req->cdb[1] = MGT_CMD_SIGNATURE; 188962306a36Sopenharmony_ci req->cdb[2] = CTLR_CONFIG_CMD; 189062306a36Sopenharmony_ci req->cdb[3] = PMIC_SHUTDOWN; 189162306a36Sopenharmony_ci req->cdb[4] = st_sleep_mic; 189262306a36Sopenharmony_ci } else { 189362306a36Sopenharmony_ci req->cdb[0] = CONTROLLER_CMD; 189462306a36Sopenharmony_ci req->cdb[1] = CTLR_POWER_STATE_CHANGE; 189562306a36Sopenharmony_ci req->cdb[2] = CTLR_POWER_SAVING; 189662306a36Sopenharmony_ci } 189762306a36Sopenharmony_ci hba->ccb[tag].cmd = NULL; 189862306a36Sopenharmony_ci hba->ccb[tag].sg_count = 0; 189962306a36Sopenharmony_ci hba->ccb[tag].sense_bufflen = 0; 190062306a36Sopenharmony_ci hba->ccb[tag].sense_buffer = NULL; 190162306a36Sopenharmony_ci hba->ccb[tag].req_type = PASSTHRU_REQ_TYPE; 190262306a36Sopenharmony_ci hba->send(hba, req, tag); 190362306a36Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 190462306a36Sopenharmony_ci before = jiffies; 190562306a36Sopenharmony_ci while (hba->ccb[tag].req_type & PASSTHRU_REQ_TYPE) { 190662306a36Sopenharmony_ci if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) { 190762306a36Sopenharmony_ci hba->ccb[tag].req_type = 0; 190862306a36Sopenharmony_ci hba->mu_status = MU_STATE_STOP; 190962306a36Sopenharmony_ci return; 191062306a36Sopenharmony_ci } 191162306a36Sopenharmony_ci msleep(1); 191262306a36Sopenharmony_ci } 191362306a36Sopenharmony_ci hba->mu_status = MU_STATE_STOP; 191462306a36Sopenharmony_ci} 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_cistatic void stex_hba_free(struct st_hba *hba) 191762306a36Sopenharmony_ci{ 191862306a36Sopenharmony_ci stex_free_irq(hba); 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci destroy_workqueue(hba->work_q); 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_ci iounmap(hba->mmio_base); 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_ci pci_release_regions(hba->pdev); 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci kfree(hba->ccb); 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci dma_free_coherent(&hba->pdev->dev, hba->dma_size, 192962306a36Sopenharmony_ci hba->dma_mem, hba->dma_handle); 193062306a36Sopenharmony_ci} 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_cistatic void stex_remove(struct pci_dev *pdev) 193362306a36Sopenharmony_ci{ 193462306a36Sopenharmony_ci struct st_hba *hba = pci_get_drvdata(pdev); 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci hba->mu_status = MU_STATE_NOCONNECT; 193762306a36Sopenharmony_ci return_abnormal_state(hba, DID_NO_CONNECT); 193862306a36Sopenharmony_ci scsi_remove_host(hba->host); 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_ci scsi_block_requests(hba->host); 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci stex_hba_free(hba); 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_ci scsi_host_put(hba->host); 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci pci_disable_device(pdev); 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ci unregister_reboot_notifier(&stex_notifier); 194962306a36Sopenharmony_ci} 195062306a36Sopenharmony_ci 195162306a36Sopenharmony_cistatic void stex_shutdown(struct pci_dev *pdev) 195262306a36Sopenharmony_ci{ 195362306a36Sopenharmony_ci struct st_hba *hba = pci_get_drvdata(pdev); 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_ci if (hba->supports_pm == 0) { 195662306a36Sopenharmony_ci stex_hba_stop(hba, ST_IGNORED); 195762306a36Sopenharmony_ci } else if (hba->supports_pm == 1 && S6flag) { 195862306a36Sopenharmony_ci unregister_reboot_notifier(&stex_notifier); 195962306a36Sopenharmony_ci stex_hba_stop(hba, ST_S6); 196062306a36Sopenharmony_ci } else 196162306a36Sopenharmony_ci stex_hba_stop(hba, ST_S5); 196262306a36Sopenharmony_ci} 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_cistatic int stex_choice_sleep_mic(struct st_hba *hba, pm_message_t state) 196562306a36Sopenharmony_ci{ 196662306a36Sopenharmony_ci switch (state.event) { 196762306a36Sopenharmony_ci case PM_EVENT_SUSPEND: 196862306a36Sopenharmony_ci return ST_S3; 196962306a36Sopenharmony_ci case PM_EVENT_HIBERNATE: 197062306a36Sopenharmony_ci hba->msi_lock = 0; 197162306a36Sopenharmony_ci return ST_S4; 197262306a36Sopenharmony_ci default: 197362306a36Sopenharmony_ci return ST_NOTHANDLED; 197462306a36Sopenharmony_ci } 197562306a36Sopenharmony_ci} 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_cistatic int stex_suspend(struct pci_dev *pdev, pm_message_t state) 197862306a36Sopenharmony_ci{ 197962306a36Sopenharmony_ci struct st_hba *hba = pci_get_drvdata(pdev); 198062306a36Sopenharmony_ci 198162306a36Sopenharmony_ci if ((hba->cardtype == st_yel || hba->cardtype == st_P3) 198262306a36Sopenharmony_ci && hba->supports_pm == 1) 198362306a36Sopenharmony_ci stex_hba_stop(hba, stex_choice_sleep_mic(hba, state)); 198462306a36Sopenharmony_ci else 198562306a36Sopenharmony_ci stex_hba_stop(hba, ST_IGNORED); 198662306a36Sopenharmony_ci return 0; 198762306a36Sopenharmony_ci} 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_cistatic int stex_resume(struct pci_dev *pdev) 199062306a36Sopenharmony_ci{ 199162306a36Sopenharmony_ci struct st_hba *hba = pci_get_drvdata(pdev); 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci hba->mu_status = MU_STATE_STARTING; 199462306a36Sopenharmony_ci stex_handshake(hba); 199562306a36Sopenharmony_ci return 0; 199662306a36Sopenharmony_ci} 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_cistatic int stex_halt(struct notifier_block *nb, unsigned long event, void *buf) 199962306a36Sopenharmony_ci{ 200062306a36Sopenharmony_ci S6flag = 1; 200162306a36Sopenharmony_ci return NOTIFY_OK; 200262306a36Sopenharmony_ci} 200362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, stex_pci_tbl); 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_cistatic struct pci_driver stex_pci_driver = { 200662306a36Sopenharmony_ci .name = DRV_NAME, 200762306a36Sopenharmony_ci .id_table = stex_pci_tbl, 200862306a36Sopenharmony_ci .probe = stex_probe, 200962306a36Sopenharmony_ci .remove = stex_remove, 201062306a36Sopenharmony_ci .shutdown = stex_shutdown, 201162306a36Sopenharmony_ci .suspend = stex_suspend, 201262306a36Sopenharmony_ci .resume = stex_resume, 201362306a36Sopenharmony_ci}; 201462306a36Sopenharmony_ci 201562306a36Sopenharmony_cistatic int __init stex_init(void) 201662306a36Sopenharmony_ci{ 201762306a36Sopenharmony_ci printk(KERN_INFO DRV_NAME 201862306a36Sopenharmony_ci ": Promise SuperTrak EX Driver version: %s\n", 201962306a36Sopenharmony_ci ST_DRIVER_VERSION); 202062306a36Sopenharmony_ci 202162306a36Sopenharmony_ci return pci_register_driver(&stex_pci_driver); 202262306a36Sopenharmony_ci} 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_cistatic void __exit stex_exit(void) 202562306a36Sopenharmony_ci{ 202662306a36Sopenharmony_ci pci_unregister_driver(&stex_pci_driver); 202762306a36Sopenharmony_ci} 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_cimodule_init(stex_init); 203062306a36Sopenharmony_cimodule_exit(stex_exit); 2031