18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * SuperTrak EX Series Storage Controller driver for Linux 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2005-2015 Promise Technology Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Written By: 88c2ecf20Sopenharmony_ci * Ed Lin <promise_linux@promise.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/errno.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/delay.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci#include <linux/time.h> 178c2ecf20Sopenharmony_ci#include <linux/pci.h> 188c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 198c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 208c2ecf20Sopenharmony_ci#include <linux/types.h> 218c2ecf20Sopenharmony_ci#include <linux/module.h> 228c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 238c2ecf20Sopenharmony_ci#include <linux/ktime.h> 248c2ecf20Sopenharmony_ci#include <linux/reboot.h> 258c2ecf20Sopenharmony_ci#include <asm/io.h> 268c2ecf20Sopenharmony_ci#include <asm/irq.h> 278c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 288c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 298c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 308c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 318c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 328c2ecf20Sopenharmony_ci#include <scsi/scsi_tcq.h> 338c2ecf20Sopenharmony_ci#include <scsi/scsi_dbg.h> 348c2ecf20Sopenharmony_ci#include <scsi/scsi_eh.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define DRV_NAME "stex" 378c2ecf20Sopenharmony_ci#define ST_DRIVER_VERSION "6.02.0000.01" 388c2ecf20Sopenharmony_ci#define ST_VER_MAJOR 6 398c2ecf20Sopenharmony_ci#define ST_VER_MINOR 02 408c2ecf20Sopenharmony_ci#define ST_OEM 0000 418c2ecf20Sopenharmony_ci#define ST_BUILD_VER 01 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cienum { 448c2ecf20Sopenharmony_ci /* MU register offset */ 458c2ecf20Sopenharmony_ci IMR0 = 0x10, /* MU_INBOUND_MESSAGE_REG0 */ 468c2ecf20Sopenharmony_ci IMR1 = 0x14, /* MU_INBOUND_MESSAGE_REG1 */ 478c2ecf20Sopenharmony_ci OMR0 = 0x18, /* MU_OUTBOUND_MESSAGE_REG0 */ 488c2ecf20Sopenharmony_ci OMR1 = 0x1c, /* MU_OUTBOUND_MESSAGE_REG1 */ 498c2ecf20Sopenharmony_ci IDBL = 0x20, /* MU_INBOUND_DOORBELL */ 508c2ecf20Sopenharmony_ci IIS = 0x24, /* MU_INBOUND_INTERRUPT_STATUS */ 518c2ecf20Sopenharmony_ci IIM = 0x28, /* MU_INBOUND_INTERRUPT_MASK */ 528c2ecf20Sopenharmony_ci ODBL = 0x2c, /* MU_OUTBOUND_DOORBELL */ 538c2ecf20Sopenharmony_ci OIS = 0x30, /* MU_OUTBOUND_INTERRUPT_STATUS */ 548c2ecf20Sopenharmony_ci OIM = 0x3c, /* MU_OUTBOUND_INTERRUPT_MASK */ 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci YIOA_STATUS = 0x00, 578c2ecf20Sopenharmony_ci YH2I_INT = 0x20, 588c2ecf20Sopenharmony_ci YINT_EN = 0x34, 598c2ecf20Sopenharmony_ci YI2H_INT = 0x9c, 608c2ecf20Sopenharmony_ci YI2H_INT_C = 0xa0, 618c2ecf20Sopenharmony_ci YH2I_REQ = 0xc0, 628c2ecf20Sopenharmony_ci YH2I_REQ_HI = 0xc4, 638c2ecf20Sopenharmony_ci PSCRATCH0 = 0xb0, 648c2ecf20Sopenharmony_ci PSCRATCH1 = 0xb4, 658c2ecf20Sopenharmony_ci PSCRATCH2 = 0xb8, 668c2ecf20Sopenharmony_ci PSCRATCH3 = 0xbc, 678c2ecf20Sopenharmony_ci PSCRATCH4 = 0xc8, 688c2ecf20Sopenharmony_ci MAILBOX_BASE = 0x1000, 698c2ecf20Sopenharmony_ci MAILBOX_HNDSHK_STS = 0x0, 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci /* MU register value */ 728c2ecf20Sopenharmony_ci MU_INBOUND_DOORBELL_HANDSHAKE = (1 << 0), 738c2ecf20Sopenharmony_ci MU_INBOUND_DOORBELL_REQHEADCHANGED = (1 << 1), 748c2ecf20Sopenharmony_ci MU_INBOUND_DOORBELL_STATUSTAILCHANGED = (1 << 2), 758c2ecf20Sopenharmony_ci MU_INBOUND_DOORBELL_HMUSTOPPED = (1 << 3), 768c2ecf20Sopenharmony_ci MU_INBOUND_DOORBELL_RESET = (1 << 4), 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci MU_OUTBOUND_DOORBELL_HANDSHAKE = (1 << 0), 798c2ecf20Sopenharmony_ci MU_OUTBOUND_DOORBELL_REQUESTTAILCHANGED = (1 << 1), 808c2ecf20Sopenharmony_ci MU_OUTBOUND_DOORBELL_STATUSHEADCHANGED = (1 << 2), 818c2ecf20Sopenharmony_ci MU_OUTBOUND_DOORBELL_BUSCHANGE = (1 << 3), 828c2ecf20Sopenharmony_ci MU_OUTBOUND_DOORBELL_HASEVENT = (1 << 4), 838c2ecf20Sopenharmony_ci MU_OUTBOUND_DOORBELL_REQUEST_RESET = (1 << 27), 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci /* MU status code */ 868c2ecf20Sopenharmony_ci MU_STATE_STARTING = 1, 878c2ecf20Sopenharmony_ci MU_STATE_STARTED = 2, 888c2ecf20Sopenharmony_ci MU_STATE_RESETTING = 3, 898c2ecf20Sopenharmony_ci MU_STATE_FAILED = 4, 908c2ecf20Sopenharmony_ci MU_STATE_STOP = 5, 918c2ecf20Sopenharmony_ci MU_STATE_NOCONNECT = 6, 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci MU_MAX_DELAY = 50, 948c2ecf20Sopenharmony_ci MU_HANDSHAKE_SIGNATURE = 0x55aaaa55, 958c2ecf20Sopenharmony_ci MU_HANDSHAKE_SIGNATURE_HALF = 0x5a5a0000, 968c2ecf20Sopenharmony_ci MU_HARD_RESET_WAIT = 30000, 978c2ecf20Sopenharmony_ci HMU_PARTNER_TYPE = 2, 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci /* firmware returned values */ 1008c2ecf20Sopenharmony_ci SRB_STATUS_SUCCESS = 0x01, 1018c2ecf20Sopenharmony_ci SRB_STATUS_ERROR = 0x04, 1028c2ecf20Sopenharmony_ci SRB_STATUS_BUSY = 0x05, 1038c2ecf20Sopenharmony_ci SRB_STATUS_INVALID_REQUEST = 0x06, 1048c2ecf20Sopenharmony_ci SRB_STATUS_SELECTION_TIMEOUT = 0x0A, 1058c2ecf20Sopenharmony_ci SRB_SEE_SENSE = 0x80, 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* task attribute */ 1088c2ecf20Sopenharmony_ci TASK_ATTRIBUTE_SIMPLE = 0x0, 1098c2ecf20Sopenharmony_ci TASK_ATTRIBUTE_HEADOFQUEUE = 0x1, 1108c2ecf20Sopenharmony_ci TASK_ATTRIBUTE_ORDERED = 0x2, 1118c2ecf20Sopenharmony_ci TASK_ATTRIBUTE_ACA = 0x4, 1128c2ecf20Sopenharmony_ci}; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cienum { 1158c2ecf20Sopenharmony_ci SS_STS_NORMAL = 0x80000000, 1168c2ecf20Sopenharmony_ci SS_STS_DONE = 0x40000000, 1178c2ecf20Sopenharmony_ci SS_STS_HANDSHAKE = 0x20000000, 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci SS_HEAD_HANDSHAKE = 0x80, 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci SS_H2I_INT_RESET = 0x100, 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci SS_I2H_REQUEST_RESET = 0x2000, 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci SS_MU_OPERATIONAL = 0x80000000, 1268c2ecf20Sopenharmony_ci}; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cienum { 1298c2ecf20Sopenharmony_ci STEX_CDB_LENGTH = 16, 1308c2ecf20Sopenharmony_ci STATUS_VAR_LEN = 128, 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* sg flags */ 1338c2ecf20Sopenharmony_ci SG_CF_EOT = 0x80, /* end of table */ 1348c2ecf20Sopenharmony_ci SG_CF_64B = 0x40, /* 64 bit item */ 1358c2ecf20Sopenharmony_ci SG_CF_HOST = 0x20, /* sg in host memory */ 1368c2ecf20Sopenharmony_ci MSG_DATA_DIR_ND = 0, 1378c2ecf20Sopenharmony_ci MSG_DATA_DIR_IN = 1, 1388c2ecf20Sopenharmony_ci MSG_DATA_DIR_OUT = 2, 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci st_shasta = 0, 1418c2ecf20Sopenharmony_ci st_vsc = 1, 1428c2ecf20Sopenharmony_ci st_yosemite = 2, 1438c2ecf20Sopenharmony_ci st_seq = 3, 1448c2ecf20Sopenharmony_ci st_yel = 4, 1458c2ecf20Sopenharmony_ci st_P3 = 5, 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci PASSTHRU_REQ_TYPE = 0x00000001, 1488c2ecf20Sopenharmony_ci PASSTHRU_REQ_NO_WAKEUP = 0x00000100, 1498c2ecf20Sopenharmony_ci ST_INTERNAL_TIMEOUT = 180, 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci ST_TO_CMD = 0, 1528c2ecf20Sopenharmony_ci ST_FROM_CMD = 1, 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* vendor specific commands of Promise */ 1558c2ecf20Sopenharmony_ci MGT_CMD = 0xd8, 1568c2ecf20Sopenharmony_ci SINBAND_MGT_CMD = 0xd9, 1578c2ecf20Sopenharmony_ci ARRAY_CMD = 0xe0, 1588c2ecf20Sopenharmony_ci CONTROLLER_CMD = 0xe1, 1598c2ecf20Sopenharmony_ci DEBUGGING_CMD = 0xe2, 1608c2ecf20Sopenharmony_ci PASSTHRU_CMD = 0xe3, 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci PASSTHRU_GET_ADAPTER = 0x05, 1638c2ecf20Sopenharmony_ci PASSTHRU_GET_DRVVER = 0x10, 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci CTLR_CONFIG_CMD = 0x03, 1668c2ecf20Sopenharmony_ci CTLR_SHUTDOWN = 0x0d, 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci CTLR_POWER_STATE_CHANGE = 0x0e, 1698c2ecf20Sopenharmony_ci CTLR_POWER_SAVING = 0x01, 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci PASSTHRU_SIGNATURE = 0x4e415041, 1728c2ecf20Sopenharmony_ci MGT_CMD_SIGNATURE = 0xba, 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci INQUIRY_EVPD = 0x01, 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci ST_ADDITIONAL_MEM = 0x200000, 1778c2ecf20Sopenharmony_ci ST_ADDITIONAL_MEM_MIN = 0x80000, 1788c2ecf20Sopenharmony_ci PMIC_SHUTDOWN = 0x0D, 1798c2ecf20Sopenharmony_ci PMIC_REUMSE = 0x10, 1808c2ecf20Sopenharmony_ci ST_IGNORED = -1, 1818c2ecf20Sopenharmony_ci ST_NOTHANDLED = 7, 1828c2ecf20Sopenharmony_ci ST_S3 = 3, 1838c2ecf20Sopenharmony_ci ST_S4 = 4, 1848c2ecf20Sopenharmony_ci ST_S5 = 5, 1858c2ecf20Sopenharmony_ci ST_S6 = 6, 1868c2ecf20Sopenharmony_ci}; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistruct st_sgitem { 1898c2ecf20Sopenharmony_ci u8 ctrl; /* SG_CF_xxx */ 1908c2ecf20Sopenharmony_ci u8 reserved[3]; 1918c2ecf20Sopenharmony_ci __le32 count; 1928c2ecf20Sopenharmony_ci __le64 addr; 1938c2ecf20Sopenharmony_ci}; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistruct st_ss_sgitem { 1968c2ecf20Sopenharmony_ci __le32 addr; 1978c2ecf20Sopenharmony_ci __le32 addr_hi; 1988c2ecf20Sopenharmony_ci __le32 count; 1998c2ecf20Sopenharmony_ci}; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistruct st_sgtable { 2028c2ecf20Sopenharmony_ci __le16 sg_count; 2038c2ecf20Sopenharmony_ci __le16 max_sg_count; 2048c2ecf20Sopenharmony_ci __le32 sz_in_byte; 2058c2ecf20Sopenharmony_ci}; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistruct st_msg_header { 2088c2ecf20Sopenharmony_ci __le64 handle; 2098c2ecf20Sopenharmony_ci u8 flag; 2108c2ecf20Sopenharmony_ci u8 channel; 2118c2ecf20Sopenharmony_ci __le16 timeout; 2128c2ecf20Sopenharmony_ci u32 reserved; 2138c2ecf20Sopenharmony_ci}; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistruct handshake_frame { 2168c2ecf20Sopenharmony_ci __le64 rb_phy; /* request payload queue physical address */ 2178c2ecf20Sopenharmony_ci __le16 req_sz; /* size of each request payload */ 2188c2ecf20Sopenharmony_ci __le16 req_cnt; /* count of reqs the buffer can hold */ 2198c2ecf20Sopenharmony_ci __le16 status_sz; /* size of each status payload */ 2208c2ecf20Sopenharmony_ci __le16 status_cnt; /* count of status the buffer can hold */ 2218c2ecf20Sopenharmony_ci __le64 hosttime; /* seconds from Jan 1, 1970 (GMT) */ 2228c2ecf20Sopenharmony_ci u8 partner_type; /* who sends this frame */ 2238c2ecf20Sopenharmony_ci u8 reserved0[7]; 2248c2ecf20Sopenharmony_ci __le32 partner_ver_major; 2258c2ecf20Sopenharmony_ci __le32 partner_ver_minor; 2268c2ecf20Sopenharmony_ci __le32 partner_ver_oem; 2278c2ecf20Sopenharmony_ci __le32 partner_ver_build; 2288c2ecf20Sopenharmony_ci __le32 extra_offset; /* NEW */ 2298c2ecf20Sopenharmony_ci __le32 extra_size; /* NEW */ 2308c2ecf20Sopenharmony_ci __le32 scratch_size; 2318c2ecf20Sopenharmony_ci u32 reserved1; 2328c2ecf20Sopenharmony_ci}; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistruct req_msg { 2358c2ecf20Sopenharmony_ci __le16 tag; 2368c2ecf20Sopenharmony_ci u8 lun; 2378c2ecf20Sopenharmony_ci u8 target; 2388c2ecf20Sopenharmony_ci u8 task_attr; 2398c2ecf20Sopenharmony_ci u8 task_manage; 2408c2ecf20Sopenharmony_ci u8 data_dir; 2418c2ecf20Sopenharmony_ci u8 payload_sz; /* payload size in 4-byte, not used */ 2428c2ecf20Sopenharmony_ci u8 cdb[STEX_CDB_LENGTH]; 2438c2ecf20Sopenharmony_ci u32 variable[]; 2448c2ecf20Sopenharmony_ci}; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistruct status_msg { 2478c2ecf20Sopenharmony_ci __le16 tag; 2488c2ecf20Sopenharmony_ci u8 lun; 2498c2ecf20Sopenharmony_ci u8 target; 2508c2ecf20Sopenharmony_ci u8 srb_status; 2518c2ecf20Sopenharmony_ci u8 scsi_status; 2528c2ecf20Sopenharmony_ci u8 reserved; 2538c2ecf20Sopenharmony_ci u8 payload_sz; /* payload size in 4-byte */ 2548c2ecf20Sopenharmony_ci u8 variable[STATUS_VAR_LEN]; 2558c2ecf20Sopenharmony_ci}; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistruct ver_info { 2588c2ecf20Sopenharmony_ci u32 major; 2598c2ecf20Sopenharmony_ci u32 minor; 2608c2ecf20Sopenharmony_ci u32 oem; 2618c2ecf20Sopenharmony_ci u32 build; 2628c2ecf20Sopenharmony_ci u32 reserved[2]; 2638c2ecf20Sopenharmony_ci}; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistruct st_frame { 2668c2ecf20Sopenharmony_ci u32 base[6]; 2678c2ecf20Sopenharmony_ci u32 rom_addr; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci struct ver_info drv_ver; 2708c2ecf20Sopenharmony_ci struct ver_info bios_ver; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci u32 bus; 2738c2ecf20Sopenharmony_ci u32 slot; 2748c2ecf20Sopenharmony_ci u32 irq_level; 2758c2ecf20Sopenharmony_ci u32 irq_vec; 2768c2ecf20Sopenharmony_ci u32 id; 2778c2ecf20Sopenharmony_ci u32 subid; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci u32 dimm_size; 2808c2ecf20Sopenharmony_ci u8 dimm_type; 2818c2ecf20Sopenharmony_ci u8 reserved[3]; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci u32 channel; 2848c2ecf20Sopenharmony_ci u32 reserved1; 2858c2ecf20Sopenharmony_ci}; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistruct st_drvver { 2888c2ecf20Sopenharmony_ci u32 major; 2898c2ecf20Sopenharmony_ci u32 minor; 2908c2ecf20Sopenharmony_ci u32 oem; 2918c2ecf20Sopenharmony_ci u32 build; 2928c2ecf20Sopenharmony_ci u32 signature[2]; 2938c2ecf20Sopenharmony_ci u8 console_id; 2948c2ecf20Sopenharmony_ci u8 host_no; 2958c2ecf20Sopenharmony_ci u8 reserved0[2]; 2968c2ecf20Sopenharmony_ci u32 reserved[3]; 2978c2ecf20Sopenharmony_ci}; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistruct st_ccb { 3008c2ecf20Sopenharmony_ci struct req_msg *req; 3018c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci void *sense_buffer; 3048c2ecf20Sopenharmony_ci unsigned int sense_bufflen; 3058c2ecf20Sopenharmony_ci int sg_count; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci u32 req_type; 3088c2ecf20Sopenharmony_ci u8 srb_status; 3098c2ecf20Sopenharmony_ci u8 scsi_status; 3108c2ecf20Sopenharmony_ci u8 reserved[2]; 3118c2ecf20Sopenharmony_ci}; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistruct st_hba { 3148c2ecf20Sopenharmony_ci void __iomem *mmio_base; /* iomapped PCI memory space */ 3158c2ecf20Sopenharmony_ci void *dma_mem; 3168c2ecf20Sopenharmony_ci dma_addr_t dma_handle; 3178c2ecf20Sopenharmony_ci size_t dma_size; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci struct Scsi_Host *host; 3208c2ecf20Sopenharmony_ci struct pci_dev *pdev; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci struct req_msg * (*alloc_rq) (struct st_hba *); 3238c2ecf20Sopenharmony_ci int (*map_sg)(struct st_hba *, struct req_msg *, struct st_ccb *); 3248c2ecf20Sopenharmony_ci void (*send) (struct st_hba *, struct req_msg *, u16); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci u32 req_head; 3278c2ecf20Sopenharmony_ci u32 req_tail; 3288c2ecf20Sopenharmony_ci u32 status_head; 3298c2ecf20Sopenharmony_ci u32 status_tail; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci struct status_msg *status_buffer; 3328c2ecf20Sopenharmony_ci void *copy_buffer; /* temp buffer for driver-handled commands */ 3338c2ecf20Sopenharmony_ci struct st_ccb *ccb; 3348c2ecf20Sopenharmony_ci struct st_ccb *wait_ccb; 3358c2ecf20Sopenharmony_ci __le32 *scratch; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci char work_q_name[20]; 3388c2ecf20Sopenharmony_ci struct workqueue_struct *work_q; 3398c2ecf20Sopenharmony_ci struct work_struct reset_work; 3408c2ecf20Sopenharmony_ci wait_queue_head_t reset_waitq; 3418c2ecf20Sopenharmony_ci unsigned int mu_status; 3428c2ecf20Sopenharmony_ci unsigned int cardtype; 3438c2ecf20Sopenharmony_ci int msi_enabled; 3448c2ecf20Sopenharmony_ci int out_req_cnt; 3458c2ecf20Sopenharmony_ci u32 extra_offset; 3468c2ecf20Sopenharmony_ci u16 rq_count; 3478c2ecf20Sopenharmony_ci u16 rq_size; 3488c2ecf20Sopenharmony_ci u16 sts_count; 3498c2ecf20Sopenharmony_ci u8 supports_pm; 3508c2ecf20Sopenharmony_ci int msi_lock; 3518c2ecf20Sopenharmony_ci}; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cistruct st_card_info { 3548c2ecf20Sopenharmony_ci struct req_msg * (*alloc_rq) (struct st_hba *); 3558c2ecf20Sopenharmony_ci int (*map_sg)(struct st_hba *, struct req_msg *, struct st_ccb *); 3568c2ecf20Sopenharmony_ci void (*send) (struct st_hba *, struct req_msg *, u16); 3578c2ecf20Sopenharmony_ci unsigned int max_id; 3588c2ecf20Sopenharmony_ci unsigned int max_lun; 3598c2ecf20Sopenharmony_ci unsigned int max_channel; 3608c2ecf20Sopenharmony_ci u16 rq_count; 3618c2ecf20Sopenharmony_ci u16 rq_size; 3628c2ecf20Sopenharmony_ci u16 sts_count; 3638c2ecf20Sopenharmony_ci}; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic int S6flag; 3668c2ecf20Sopenharmony_cistatic int stex_halt(struct notifier_block *nb, ulong event, void *buf); 3678c2ecf20Sopenharmony_cistatic struct notifier_block stex_notifier = { 3688c2ecf20Sopenharmony_ci stex_halt, NULL, 0 3698c2ecf20Sopenharmony_ci}; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic int msi; 3728c2ecf20Sopenharmony_cimodule_param(msi, int, 0); 3738c2ecf20Sopenharmony_ciMODULE_PARM_DESC(msi, "Enable Message Signaled Interrupts(0=off, 1=on)"); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic const char console_inq_page[] = 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci 0x03,0x00,0x03,0x03,0xFA,0x00,0x00,0x30, 3788c2ecf20Sopenharmony_ci 0x50,0x72,0x6F,0x6D,0x69,0x73,0x65,0x20, /* "Promise " */ 3798c2ecf20Sopenharmony_ci 0x52,0x41,0x49,0x44,0x20,0x43,0x6F,0x6E, /* "RAID Con" */ 3808c2ecf20Sopenharmony_ci 0x73,0x6F,0x6C,0x65,0x20,0x20,0x20,0x20, /* "sole " */ 3818c2ecf20Sopenharmony_ci 0x31,0x2E,0x30,0x30,0x20,0x20,0x20,0x20, /* "1.00 " */ 3828c2ecf20Sopenharmony_ci 0x53,0x58,0x2F,0x52,0x53,0x41,0x46,0x2D, /* "SX/RSAF-" */ 3838c2ecf20Sopenharmony_ci 0x54,0x45,0x31,0x2E,0x30,0x30,0x20,0x20, /* "TE1.00 " */ 3848c2ecf20Sopenharmony_ci 0x0C,0x20,0x20,0x20,0x20,0x20,0x20,0x20 3858c2ecf20Sopenharmony_ci}; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ed Lin"); 3888c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Promise Technology SuperTrak EX Controllers"); 3898c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 3908c2ecf20Sopenharmony_ciMODULE_VERSION(ST_DRIVER_VERSION); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic struct status_msg *stex_get_status(struct st_hba *hba) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci struct status_msg *status = hba->status_buffer + hba->status_tail; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci ++hba->status_tail; 3978c2ecf20Sopenharmony_ci hba->status_tail %= hba->sts_count+1; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci return status; 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic void stex_invalid_field(struct scsi_cmnd *cmd, 4038c2ecf20Sopenharmony_ci void (*done)(struct scsi_cmnd *)) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci /* "Invalid field in cdb" */ 4088c2ecf20Sopenharmony_ci scsi_build_sense_buffer(0, cmd->sense_buffer, ILLEGAL_REQUEST, 0x24, 4098c2ecf20Sopenharmony_ci 0x0); 4108c2ecf20Sopenharmony_ci done(cmd); 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cistatic struct req_msg *stex_alloc_req(struct st_hba *hba) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci struct req_msg *req = hba->dma_mem + hba->req_head * hba->rq_size; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci ++hba->req_head; 4188c2ecf20Sopenharmony_ci hba->req_head %= hba->rq_count+1; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci return req; 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic struct req_msg *stex_ss_alloc_req(struct st_hba *hba) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci return (struct req_msg *)(hba->dma_mem + 4268c2ecf20Sopenharmony_ci hba->req_head * hba->rq_size + sizeof(struct st_msg_header)); 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cistatic int stex_map_sg(struct st_hba *hba, 4308c2ecf20Sopenharmony_ci struct req_msg *req, struct st_ccb *ccb) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd; 4338c2ecf20Sopenharmony_ci struct scatterlist *sg; 4348c2ecf20Sopenharmony_ci struct st_sgtable *dst; 4358c2ecf20Sopenharmony_ci struct st_sgitem *table; 4368c2ecf20Sopenharmony_ci int i, nseg; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci cmd = ccb->cmd; 4398c2ecf20Sopenharmony_ci nseg = scsi_dma_map(cmd); 4408c2ecf20Sopenharmony_ci BUG_ON(nseg < 0); 4418c2ecf20Sopenharmony_ci if (nseg) { 4428c2ecf20Sopenharmony_ci dst = (struct st_sgtable *)req->variable; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci ccb->sg_count = nseg; 4458c2ecf20Sopenharmony_ci dst->sg_count = cpu_to_le16((u16)nseg); 4468c2ecf20Sopenharmony_ci dst->max_sg_count = cpu_to_le16(hba->host->sg_tablesize); 4478c2ecf20Sopenharmony_ci dst->sz_in_byte = cpu_to_le32(scsi_bufflen(cmd)); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci table = (struct st_sgitem *)(dst + 1); 4508c2ecf20Sopenharmony_ci scsi_for_each_sg(cmd, sg, nseg, i) { 4518c2ecf20Sopenharmony_ci table[i].count = cpu_to_le32((u32)sg_dma_len(sg)); 4528c2ecf20Sopenharmony_ci table[i].addr = cpu_to_le64(sg_dma_address(sg)); 4538c2ecf20Sopenharmony_ci table[i].ctrl = SG_CF_64B | SG_CF_HOST; 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci table[--i].ctrl |= SG_CF_EOT; 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci return nseg; 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic int stex_ss_map_sg(struct st_hba *hba, 4628c2ecf20Sopenharmony_ci struct req_msg *req, struct st_ccb *ccb) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd; 4658c2ecf20Sopenharmony_ci struct scatterlist *sg; 4668c2ecf20Sopenharmony_ci struct st_sgtable *dst; 4678c2ecf20Sopenharmony_ci struct st_ss_sgitem *table; 4688c2ecf20Sopenharmony_ci int i, nseg; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci cmd = ccb->cmd; 4718c2ecf20Sopenharmony_ci nseg = scsi_dma_map(cmd); 4728c2ecf20Sopenharmony_ci BUG_ON(nseg < 0); 4738c2ecf20Sopenharmony_ci if (nseg) { 4748c2ecf20Sopenharmony_ci dst = (struct st_sgtable *)req->variable; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci ccb->sg_count = nseg; 4778c2ecf20Sopenharmony_ci dst->sg_count = cpu_to_le16((u16)nseg); 4788c2ecf20Sopenharmony_ci dst->max_sg_count = cpu_to_le16(hba->host->sg_tablesize); 4798c2ecf20Sopenharmony_ci dst->sz_in_byte = cpu_to_le32(scsi_bufflen(cmd)); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci table = (struct st_ss_sgitem *)(dst + 1); 4828c2ecf20Sopenharmony_ci scsi_for_each_sg(cmd, sg, nseg, i) { 4838c2ecf20Sopenharmony_ci table[i].count = cpu_to_le32((u32)sg_dma_len(sg)); 4848c2ecf20Sopenharmony_ci table[i].addr = 4858c2ecf20Sopenharmony_ci cpu_to_le32(sg_dma_address(sg) & 0xffffffff); 4868c2ecf20Sopenharmony_ci table[i].addr_hi = 4878c2ecf20Sopenharmony_ci cpu_to_le32((sg_dma_address(sg) >> 16) >> 16); 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci return nseg; 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic void stex_controller_info(struct st_hba *hba, struct st_ccb *ccb) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci struct st_frame *p; 4978c2ecf20Sopenharmony_ci size_t count = sizeof(struct st_frame); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci p = hba->copy_buffer; 5008c2ecf20Sopenharmony_ci scsi_sg_copy_to_buffer(ccb->cmd, p, count); 5018c2ecf20Sopenharmony_ci memset(p->base, 0, sizeof(u32)*6); 5028c2ecf20Sopenharmony_ci *(unsigned long *)(p->base) = pci_resource_start(hba->pdev, 0); 5038c2ecf20Sopenharmony_ci p->rom_addr = 0; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci p->drv_ver.major = ST_VER_MAJOR; 5068c2ecf20Sopenharmony_ci p->drv_ver.minor = ST_VER_MINOR; 5078c2ecf20Sopenharmony_ci p->drv_ver.oem = ST_OEM; 5088c2ecf20Sopenharmony_ci p->drv_ver.build = ST_BUILD_VER; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci p->bus = hba->pdev->bus->number; 5118c2ecf20Sopenharmony_ci p->slot = hba->pdev->devfn; 5128c2ecf20Sopenharmony_ci p->irq_level = 0; 5138c2ecf20Sopenharmony_ci p->irq_vec = hba->pdev->irq; 5148c2ecf20Sopenharmony_ci p->id = hba->pdev->vendor << 16 | hba->pdev->device; 5158c2ecf20Sopenharmony_ci p->subid = 5168c2ecf20Sopenharmony_ci hba->pdev->subsystem_vendor << 16 | hba->pdev->subsystem_device; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci scsi_sg_copy_from_buffer(ccb->cmd, p, count); 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic void 5228c2ecf20Sopenharmony_cistex_send_cmd(struct st_hba *hba, struct req_msg *req, u16 tag) 5238c2ecf20Sopenharmony_ci{ 5248c2ecf20Sopenharmony_ci req->tag = cpu_to_le16(tag); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci hba->ccb[tag].req = req; 5278c2ecf20Sopenharmony_ci hba->out_req_cnt++; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci writel(hba->req_head, hba->mmio_base + IMR0); 5308c2ecf20Sopenharmony_ci writel(MU_INBOUND_DOORBELL_REQHEADCHANGED, hba->mmio_base + IDBL); 5318c2ecf20Sopenharmony_ci readl(hba->mmio_base + IDBL); /* flush */ 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_cistatic void 5358c2ecf20Sopenharmony_cistex_ss_send_cmd(struct st_hba *hba, struct req_msg *req, u16 tag) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd; 5388c2ecf20Sopenharmony_ci struct st_msg_header *msg_h; 5398c2ecf20Sopenharmony_ci dma_addr_t addr; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci req->tag = cpu_to_le16(tag); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci hba->ccb[tag].req = req; 5448c2ecf20Sopenharmony_ci hba->out_req_cnt++; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci cmd = hba->ccb[tag].cmd; 5478c2ecf20Sopenharmony_ci msg_h = (struct st_msg_header *)req - 1; 5488c2ecf20Sopenharmony_ci if (likely(cmd)) { 5498c2ecf20Sopenharmony_ci msg_h->channel = (u8)cmd->device->channel; 5508c2ecf20Sopenharmony_ci msg_h->timeout = cpu_to_le16(cmd->request->timeout/HZ); 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci addr = hba->dma_handle + hba->req_head * hba->rq_size; 5538c2ecf20Sopenharmony_ci addr += (hba->ccb[tag].sg_count+4)/11; 5548c2ecf20Sopenharmony_ci msg_h->handle = cpu_to_le64(addr); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci ++hba->req_head; 5578c2ecf20Sopenharmony_ci hba->req_head %= hba->rq_count+1; 5588c2ecf20Sopenharmony_ci if (hba->cardtype == st_P3) { 5598c2ecf20Sopenharmony_ci writel((addr >> 16) >> 16, hba->mmio_base + YH2I_REQ_HI); 5608c2ecf20Sopenharmony_ci writel(addr, hba->mmio_base + YH2I_REQ); 5618c2ecf20Sopenharmony_ci } else { 5628c2ecf20Sopenharmony_ci writel((addr >> 16) >> 16, hba->mmio_base + YH2I_REQ_HI); 5638c2ecf20Sopenharmony_ci readl(hba->mmio_base + YH2I_REQ_HI); /* flush */ 5648c2ecf20Sopenharmony_ci writel(addr, hba->mmio_base + YH2I_REQ); 5658c2ecf20Sopenharmony_ci readl(hba->mmio_base + YH2I_REQ); /* flush */ 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci} 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_cistatic void return_abnormal_state(struct st_hba *hba, int status) 5708c2ecf20Sopenharmony_ci{ 5718c2ecf20Sopenharmony_ci struct st_ccb *ccb; 5728c2ecf20Sopenharmony_ci unsigned long flags; 5738c2ecf20Sopenharmony_ci u16 tag; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci spin_lock_irqsave(hba->host->host_lock, flags); 5768c2ecf20Sopenharmony_ci for (tag = 0; tag < hba->host->can_queue; tag++) { 5778c2ecf20Sopenharmony_ci ccb = &hba->ccb[tag]; 5788c2ecf20Sopenharmony_ci if (ccb->req == NULL) 5798c2ecf20Sopenharmony_ci continue; 5808c2ecf20Sopenharmony_ci ccb->req = NULL; 5818c2ecf20Sopenharmony_ci if (ccb->cmd) { 5828c2ecf20Sopenharmony_ci scsi_dma_unmap(ccb->cmd); 5838c2ecf20Sopenharmony_ci ccb->cmd->result = status << 16; 5848c2ecf20Sopenharmony_ci ccb->cmd->scsi_done(ccb->cmd); 5858c2ecf20Sopenharmony_ci ccb->cmd = NULL; 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_cistatic int 5918c2ecf20Sopenharmony_cistex_slave_config(struct scsi_device *sdev) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci sdev->use_10_for_rw = 1; 5948c2ecf20Sopenharmony_ci sdev->use_10_for_ms = 1; 5958c2ecf20Sopenharmony_ci blk_queue_rq_timeout(sdev->request_queue, 60 * HZ); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci return 0; 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_cistatic int 6018c2ecf20Sopenharmony_cistex_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) 6028c2ecf20Sopenharmony_ci{ 6038c2ecf20Sopenharmony_ci struct st_hba *hba; 6048c2ecf20Sopenharmony_ci struct Scsi_Host *host; 6058c2ecf20Sopenharmony_ci unsigned int id, lun; 6068c2ecf20Sopenharmony_ci struct req_msg *req; 6078c2ecf20Sopenharmony_ci u16 tag; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci host = cmd->device->host; 6108c2ecf20Sopenharmony_ci id = cmd->device->id; 6118c2ecf20Sopenharmony_ci lun = cmd->device->lun; 6128c2ecf20Sopenharmony_ci hba = (struct st_hba *) &host->hostdata[0]; 6138c2ecf20Sopenharmony_ci if (hba->mu_status == MU_STATE_NOCONNECT) { 6148c2ecf20Sopenharmony_ci cmd->result = DID_NO_CONNECT; 6158c2ecf20Sopenharmony_ci done(cmd); 6168c2ecf20Sopenharmony_ci return 0; 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci if (unlikely(hba->mu_status != MU_STATE_STARTED)) 6198c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci switch (cmd->cmnd[0]) { 6228c2ecf20Sopenharmony_ci case MODE_SENSE_10: 6238c2ecf20Sopenharmony_ci { 6248c2ecf20Sopenharmony_ci static char ms10_caching_page[12] = 6258c2ecf20Sopenharmony_ci { 0, 0x12, 0, 0, 0, 0, 0, 0, 0x8, 0xa, 0x4, 0 }; 6268c2ecf20Sopenharmony_ci unsigned char page; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci page = cmd->cmnd[2] & 0x3f; 6298c2ecf20Sopenharmony_ci if (page == 0x8 || page == 0x3f) { 6308c2ecf20Sopenharmony_ci scsi_sg_copy_from_buffer(cmd, ms10_caching_page, 6318c2ecf20Sopenharmony_ci sizeof(ms10_caching_page)); 6328c2ecf20Sopenharmony_ci cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; 6338c2ecf20Sopenharmony_ci done(cmd); 6348c2ecf20Sopenharmony_ci } else 6358c2ecf20Sopenharmony_ci stex_invalid_field(cmd, done); 6368c2ecf20Sopenharmony_ci return 0; 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci case REPORT_LUNS: 6398c2ecf20Sopenharmony_ci /* 6408c2ecf20Sopenharmony_ci * The shasta firmware does not report actual luns in the 6418c2ecf20Sopenharmony_ci * target, so fail the command to force sequential lun scan. 6428c2ecf20Sopenharmony_ci * Also, the console device does not support this command. 6438c2ecf20Sopenharmony_ci */ 6448c2ecf20Sopenharmony_ci if (hba->cardtype == st_shasta || id == host->max_id - 1) { 6458c2ecf20Sopenharmony_ci stex_invalid_field(cmd, done); 6468c2ecf20Sopenharmony_ci return 0; 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci break; 6498c2ecf20Sopenharmony_ci case TEST_UNIT_READY: 6508c2ecf20Sopenharmony_ci if (id == host->max_id - 1) { 6518c2ecf20Sopenharmony_ci cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; 6528c2ecf20Sopenharmony_ci done(cmd); 6538c2ecf20Sopenharmony_ci return 0; 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci break; 6568c2ecf20Sopenharmony_ci case INQUIRY: 6578c2ecf20Sopenharmony_ci if (lun >= host->max_lun) { 6588c2ecf20Sopenharmony_ci cmd->result = DID_NO_CONNECT << 16; 6598c2ecf20Sopenharmony_ci done(cmd); 6608c2ecf20Sopenharmony_ci return 0; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci if (id != host->max_id - 1) 6638c2ecf20Sopenharmony_ci break; 6648c2ecf20Sopenharmony_ci if (!lun && !cmd->device->channel && 6658c2ecf20Sopenharmony_ci (cmd->cmnd[1] & INQUIRY_EVPD) == 0) { 6668c2ecf20Sopenharmony_ci scsi_sg_copy_from_buffer(cmd, (void *)console_inq_page, 6678c2ecf20Sopenharmony_ci sizeof(console_inq_page)); 6688c2ecf20Sopenharmony_ci cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; 6698c2ecf20Sopenharmony_ci done(cmd); 6708c2ecf20Sopenharmony_ci } else 6718c2ecf20Sopenharmony_ci stex_invalid_field(cmd, done); 6728c2ecf20Sopenharmony_ci return 0; 6738c2ecf20Sopenharmony_ci case PASSTHRU_CMD: 6748c2ecf20Sopenharmony_ci if (cmd->cmnd[1] == PASSTHRU_GET_DRVVER) { 6758c2ecf20Sopenharmony_ci const struct st_drvver ver = { 6768c2ecf20Sopenharmony_ci .major = ST_VER_MAJOR, 6778c2ecf20Sopenharmony_ci .minor = ST_VER_MINOR, 6788c2ecf20Sopenharmony_ci .oem = ST_OEM, 6798c2ecf20Sopenharmony_ci .build = ST_BUILD_VER, 6808c2ecf20Sopenharmony_ci .signature[0] = PASSTHRU_SIGNATURE, 6818c2ecf20Sopenharmony_ci .console_id = host->max_id - 1, 6828c2ecf20Sopenharmony_ci .host_no = hba->host->host_no, 6838c2ecf20Sopenharmony_ci }; 6848c2ecf20Sopenharmony_ci size_t cp_len = sizeof(ver); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci cp_len = scsi_sg_copy_from_buffer(cmd, &ver, cp_len); 6878c2ecf20Sopenharmony_ci cmd->result = sizeof(ver) == cp_len ? 6888c2ecf20Sopenharmony_ci DID_OK << 16 | COMMAND_COMPLETE << 8 : 6898c2ecf20Sopenharmony_ci DID_ERROR << 16 | COMMAND_COMPLETE << 8; 6908c2ecf20Sopenharmony_ci done(cmd); 6918c2ecf20Sopenharmony_ci return 0; 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci default: 6948c2ecf20Sopenharmony_ci break; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci cmd->scsi_done = done; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci tag = cmd->request->tag; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (unlikely(tag >= host->can_queue)) 7028c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci req = hba->alloc_rq(hba); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci req->lun = lun; 7078c2ecf20Sopenharmony_ci req->target = id; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci /* cdb */ 7108c2ecf20Sopenharmony_ci memcpy(req->cdb, cmd->cmnd, STEX_CDB_LENGTH); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci if (cmd->sc_data_direction == DMA_FROM_DEVICE) 7138c2ecf20Sopenharmony_ci req->data_dir = MSG_DATA_DIR_IN; 7148c2ecf20Sopenharmony_ci else if (cmd->sc_data_direction == DMA_TO_DEVICE) 7158c2ecf20Sopenharmony_ci req->data_dir = MSG_DATA_DIR_OUT; 7168c2ecf20Sopenharmony_ci else 7178c2ecf20Sopenharmony_ci req->data_dir = MSG_DATA_DIR_ND; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci hba->ccb[tag].cmd = cmd; 7208c2ecf20Sopenharmony_ci hba->ccb[tag].sense_bufflen = SCSI_SENSE_BUFFERSIZE; 7218c2ecf20Sopenharmony_ci hba->ccb[tag].sense_buffer = cmd->sense_buffer; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci if (!hba->map_sg(hba, req, &hba->ccb[tag])) { 7248c2ecf20Sopenharmony_ci hba->ccb[tag].sg_count = 0; 7258c2ecf20Sopenharmony_ci memset(&req->variable[0], 0, 8); 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci hba->send(hba, req, tag); 7298c2ecf20Sopenharmony_ci return 0; 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_cistatic DEF_SCSI_QCMD(stex_queuecommand) 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_cistatic void stex_scsi_done(struct st_ccb *ccb) 7358c2ecf20Sopenharmony_ci{ 7368c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd = ccb->cmd; 7378c2ecf20Sopenharmony_ci int result; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci if (ccb->srb_status == SRB_STATUS_SUCCESS || ccb->srb_status == 0) { 7408c2ecf20Sopenharmony_ci result = ccb->scsi_status; 7418c2ecf20Sopenharmony_ci switch (ccb->scsi_status) { 7428c2ecf20Sopenharmony_ci case SAM_STAT_GOOD: 7438c2ecf20Sopenharmony_ci result |= DID_OK << 16 | COMMAND_COMPLETE << 8; 7448c2ecf20Sopenharmony_ci break; 7458c2ecf20Sopenharmony_ci case SAM_STAT_CHECK_CONDITION: 7468c2ecf20Sopenharmony_ci result |= DRIVER_SENSE << 24; 7478c2ecf20Sopenharmony_ci break; 7488c2ecf20Sopenharmony_ci case SAM_STAT_BUSY: 7498c2ecf20Sopenharmony_ci result |= DID_BUS_BUSY << 16 | COMMAND_COMPLETE << 8; 7508c2ecf20Sopenharmony_ci break; 7518c2ecf20Sopenharmony_ci default: 7528c2ecf20Sopenharmony_ci result |= DID_ERROR << 16 | COMMAND_COMPLETE << 8; 7538c2ecf20Sopenharmony_ci break; 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci else if (ccb->srb_status & SRB_SEE_SENSE) 7578c2ecf20Sopenharmony_ci result = DRIVER_SENSE << 24 | SAM_STAT_CHECK_CONDITION; 7588c2ecf20Sopenharmony_ci else switch (ccb->srb_status) { 7598c2ecf20Sopenharmony_ci case SRB_STATUS_SELECTION_TIMEOUT: 7608c2ecf20Sopenharmony_ci result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8; 7618c2ecf20Sopenharmony_ci break; 7628c2ecf20Sopenharmony_ci case SRB_STATUS_BUSY: 7638c2ecf20Sopenharmony_ci result = DID_BUS_BUSY << 16 | COMMAND_COMPLETE << 8; 7648c2ecf20Sopenharmony_ci break; 7658c2ecf20Sopenharmony_ci case SRB_STATUS_INVALID_REQUEST: 7668c2ecf20Sopenharmony_ci case SRB_STATUS_ERROR: 7678c2ecf20Sopenharmony_ci default: 7688c2ecf20Sopenharmony_ci result = DID_ERROR << 16 | COMMAND_COMPLETE << 8; 7698c2ecf20Sopenharmony_ci break; 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci cmd->result = result; 7738c2ecf20Sopenharmony_ci cmd->scsi_done(cmd); 7748c2ecf20Sopenharmony_ci} 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_cistatic void stex_copy_data(struct st_ccb *ccb, 7778c2ecf20Sopenharmony_ci struct status_msg *resp, unsigned int variable) 7788c2ecf20Sopenharmony_ci{ 7798c2ecf20Sopenharmony_ci if (resp->scsi_status != SAM_STAT_GOOD) { 7808c2ecf20Sopenharmony_ci if (ccb->sense_buffer != NULL) 7818c2ecf20Sopenharmony_ci memcpy(ccb->sense_buffer, resp->variable, 7828c2ecf20Sopenharmony_ci min(variable, ccb->sense_bufflen)); 7838c2ecf20Sopenharmony_ci return; 7848c2ecf20Sopenharmony_ci } 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci if (ccb->cmd == NULL) 7878c2ecf20Sopenharmony_ci return; 7888c2ecf20Sopenharmony_ci scsi_sg_copy_from_buffer(ccb->cmd, resp->variable, variable); 7898c2ecf20Sopenharmony_ci} 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_cistatic void stex_check_cmd(struct st_hba *hba, 7928c2ecf20Sopenharmony_ci struct st_ccb *ccb, struct status_msg *resp) 7938c2ecf20Sopenharmony_ci{ 7948c2ecf20Sopenharmony_ci if (ccb->cmd->cmnd[0] == MGT_CMD && 7958c2ecf20Sopenharmony_ci resp->scsi_status != SAM_STAT_CHECK_CONDITION) 7968c2ecf20Sopenharmony_ci scsi_set_resid(ccb->cmd, scsi_bufflen(ccb->cmd) - 7978c2ecf20Sopenharmony_ci le32_to_cpu(*(__le32 *)&resp->variable[0])); 7988c2ecf20Sopenharmony_ci} 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_cistatic void stex_mu_intr(struct st_hba *hba, u32 doorbell) 8018c2ecf20Sopenharmony_ci{ 8028c2ecf20Sopenharmony_ci void __iomem *base = hba->mmio_base; 8038c2ecf20Sopenharmony_ci struct status_msg *resp; 8048c2ecf20Sopenharmony_ci struct st_ccb *ccb; 8058c2ecf20Sopenharmony_ci unsigned int size; 8068c2ecf20Sopenharmony_ci u16 tag; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci if (unlikely(!(doorbell & MU_OUTBOUND_DOORBELL_STATUSHEADCHANGED))) 8098c2ecf20Sopenharmony_ci return; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci /* status payloads */ 8128c2ecf20Sopenharmony_ci hba->status_head = readl(base + OMR1); 8138c2ecf20Sopenharmony_ci if (unlikely(hba->status_head > hba->sts_count)) { 8148c2ecf20Sopenharmony_ci printk(KERN_WARNING DRV_NAME "(%s): invalid status head\n", 8158c2ecf20Sopenharmony_ci pci_name(hba->pdev)); 8168c2ecf20Sopenharmony_ci return; 8178c2ecf20Sopenharmony_ci } 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci /* 8208c2ecf20Sopenharmony_ci * it's not a valid status payload if: 8218c2ecf20Sopenharmony_ci * 1. there are no pending requests(e.g. during init stage) 8228c2ecf20Sopenharmony_ci * 2. there are some pending requests, but the controller is in 8238c2ecf20Sopenharmony_ci * reset status, and its type is not st_yosemite 8248c2ecf20Sopenharmony_ci * firmware of st_yosemite in reset status will return pending requests 8258c2ecf20Sopenharmony_ci * to driver, so we allow it to pass 8268c2ecf20Sopenharmony_ci */ 8278c2ecf20Sopenharmony_ci if (unlikely(hba->out_req_cnt <= 0 || 8288c2ecf20Sopenharmony_ci (hba->mu_status == MU_STATE_RESETTING && 8298c2ecf20Sopenharmony_ci hba->cardtype != st_yosemite))) { 8308c2ecf20Sopenharmony_ci hba->status_tail = hba->status_head; 8318c2ecf20Sopenharmony_ci goto update_status; 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci while (hba->status_tail != hba->status_head) { 8358c2ecf20Sopenharmony_ci resp = stex_get_status(hba); 8368c2ecf20Sopenharmony_ci tag = le16_to_cpu(resp->tag); 8378c2ecf20Sopenharmony_ci if (unlikely(tag >= hba->host->can_queue)) { 8388c2ecf20Sopenharmony_ci printk(KERN_WARNING DRV_NAME 8398c2ecf20Sopenharmony_ci "(%s): invalid tag\n", pci_name(hba->pdev)); 8408c2ecf20Sopenharmony_ci continue; 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci hba->out_req_cnt--; 8448c2ecf20Sopenharmony_ci ccb = &hba->ccb[tag]; 8458c2ecf20Sopenharmony_ci if (unlikely(hba->wait_ccb == ccb)) 8468c2ecf20Sopenharmony_ci hba->wait_ccb = NULL; 8478c2ecf20Sopenharmony_ci if (unlikely(ccb->req == NULL)) { 8488c2ecf20Sopenharmony_ci printk(KERN_WARNING DRV_NAME 8498c2ecf20Sopenharmony_ci "(%s): lagging req\n", pci_name(hba->pdev)); 8508c2ecf20Sopenharmony_ci continue; 8518c2ecf20Sopenharmony_ci } 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci size = resp->payload_sz * sizeof(u32); /* payload size */ 8548c2ecf20Sopenharmony_ci if (unlikely(size < sizeof(*resp) - STATUS_VAR_LEN || 8558c2ecf20Sopenharmony_ci size > sizeof(*resp))) { 8568c2ecf20Sopenharmony_ci printk(KERN_WARNING DRV_NAME "(%s): bad status size\n", 8578c2ecf20Sopenharmony_ci pci_name(hba->pdev)); 8588c2ecf20Sopenharmony_ci } else { 8598c2ecf20Sopenharmony_ci size -= sizeof(*resp) - STATUS_VAR_LEN; /* copy size */ 8608c2ecf20Sopenharmony_ci if (size) 8618c2ecf20Sopenharmony_ci stex_copy_data(ccb, resp, size); 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci ccb->req = NULL; 8658c2ecf20Sopenharmony_ci ccb->srb_status = resp->srb_status; 8668c2ecf20Sopenharmony_ci ccb->scsi_status = resp->scsi_status; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci if (likely(ccb->cmd != NULL)) { 8698c2ecf20Sopenharmony_ci if (hba->cardtype == st_yosemite) 8708c2ecf20Sopenharmony_ci stex_check_cmd(hba, ccb, resp); 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci if (unlikely(ccb->cmd->cmnd[0] == PASSTHRU_CMD && 8738c2ecf20Sopenharmony_ci ccb->cmd->cmnd[1] == PASSTHRU_GET_ADAPTER)) 8748c2ecf20Sopenharmony_ci stex_controller_info(hba, ccb); 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci scsi_dma_unmap(ccb->cmd); 8778c2ecf20Sopenharmony_ci stex_scsi_done(ccb); 8788c2ecf20Sopenharmony_ci } else 8798c2ecf20Sopenharmony_ci ccb->req_type = 0; 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ciupdate_status: 8838c2ecf20Sopenharmony_ci writel(hba->status_head, base + IMR1); 8848c2ecf20Sopenharmony_ci readl(base + IMR1); /* flush */ 8858c2ecf20Sopenharmony_ci} 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_cistatic irqreturn_t stex_intr(int irq, void *__hba) 8888c2ecf20Sopenharmony_ci{ 8898c2ecf20Sopenharmony_ci struct st_hba *hba = __hba; 8908c2ecf20Sopenharmony_ci void __iomem *base = hba->mmio_base; 8918c2ecf20Sopenharmony_ci u32 data; 8928c2ecf20Sopenharmony_ci unsigned long flags; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci spin_lock_irqsave(hba->host->host_lock, flags); 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci data = readl(base + ODBL); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci if (data && data != 0xffffffff) { 8998c2ecf20Sopenharmony_ci /* clear the interrupt */ 9008c2ecf20Sopenharmony_ci writel(data, base + ODBL); 9018c2ecf20Sopenharmony_ci readl(base + ODBL); /* flush */ 9028c2ecf20Sopenharmony_ci stex_mu_intr(hba, data); 9038c2ecf20Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 9048c2ecf20Sopenharmony_ci if (unlikely(data & MU_OUTBOUND_DOORBELL_REQUEST_RESET && 9058c2ecf20Sopenharmony_ci hba->cardtype == st_shasta)) 9068c2ecf20Sopenharmony_ci queue_work(hba->work_q, &hba->reset_work); 9078c2ecf20Sopenharmony_ci return IRQ_HANDLED; 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci return IRQ_NONE; 9138c2ecf20Sopenharmony_ci} 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_cistatic void stex_ss_mu_intr(struct st_hba *hba) 9168c2ecf20Sopenharmony_ci{ 9178c2ecf20Sopenharmony_ci struct status_msg *resp; 9188c2ecf20Sopenharmony_ci struct st_ccb *ccb; 9198c2ecf20Sopenharmony_ci __le32 *scratch; 9208c2ecf20Sopenharmony_ci unsigned int size; 9218c2ecf20Sopenharmony_ci int count = 0; 9228c2ecf20Sopenharmony_ci u32 value; 9238c2ecf20Sopenharmony_ci u16 tag; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci if (unlikely(hba->out_req_cnt <= 0 || 9268c2ecf20Sopenharmony_ci hba->mu_status == MU_STATE_RESETTING)) 9278c2ecf20Sopenharmony_ci return; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci while (count < hba->sts_count) { 9308c2ecf20Sopenharmony_ci scratch = hba->scratch + hba->status_tail; 9318c2ecf20Sopenharmony_ci value = le32_to_cpu(*scratch); 9328c2ecf20Sopenharmony_ci if (unlikely(!(value & SS_STS_NORMAL))) 9338c2ecf20Sopenharmony_ci return; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci resp = hba->status_buffer + hba->status_tail; 9368c2ecf20Sopenharmony_ci *scratch = 0; 9378c2ecf20Sopenharmony_ci ++count; 9388c2ecf20Sopenharmony_ci ++hba->status_tail; 9398c2ecf20Sopenharmony_ci hba->status_tail %= hba->sts_count+1; 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci tag = (u16)value; 9428c2ecf20Sopenharmony_ci if (unlikely(tag >= hba->host->can_queue)) { 9438c2ecf20Sopenharmony_ci printk(KERN_WARNING DRV_NAME 9448c2ecf20Sopenharmony_ci "(%s): invalid tag\n", pci_name(hba->pdev)); 9458c2ecf20Sopenharmony_ci continue; 9468c2ecf20Sopenharmony_ci } 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci hba->out_req_cnt--; 9498c2ecf20Sopenharmony_ci ccb = &hba->ccb[tag]; 9508c2ecf20Sopenharmony_ci if (unlikely(hba->wait_ccb == ccb)) 9518c2ecf20Sopenharmony_ci hba->wait_ccb = NULL; 9528c2ecf20Sopenharmony_ci if (unlikely(ccb->req == NULL)) { 9538c2ecf20Sopenharmony_ci printk(KERN_WARNING DRV_NAME 9548c2ecf20Sopenharmony_ci "(%s): lagging req\n", pci_name(hba->pdev)); 9558c2ecf20Sopenharmony_ci continue; 9568c2ecf20Sopenharmony_ci } 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci ccb->req = NULL; 9598c2ecf20Sopenharmony_ci if (likely(value & SS_STS_DONE)) { /* normal case */ 9608c2ecf20Sopenharmony_ci ccb->srb_status = SRB_STATUS_SUCCESS; 9618c2ecf20Sopenharmony_ci ccb->scsi_status = SAM_STAT_GOOD; 9628c2ecf20Sopenharmony_ci } else { 9638c2ecf20Sopenharmony_ci ccb->srb_status = resp->srb_status; 9648c2ecf20Sopenharmony_ci ccb->scsi_status = resp->scsi_status; 9658c2ecf20Sopenharmony_ci size = resp->payload_sz * sizeof(u32); 9668c2ecf20Sopenharmony_ci if (unlikely(size < sizeof(*resp) - STATUS_VAR_LEN || 9678c2ecf20Sopenharmony_ci size > sizeof(*resp))) { 9688c2ecf20Sopenharmony_ci printk(KERN_WARNING DRV_NAME 9698c2ecf20Sopenharmony_ci "(%s): bad status size\n", 9708c2ecf20Sopenharmony_ci pci_name(hba->pdev)); 9718c2ecf20Sopenharmony_ci } else { 9728c2ecf20Sopenharmony_ci size -= sizeof(*resp) - STATUS_VAR_LEN; 9738c2ecf20Sopenharmony_ci if (size) 9748c2ecf20Sopenharmony_ci stex_copy_data(ccb, resp, size); 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci if (likely(ccb->cmd != NULL)) 9778c2ecf20Sopenharmony_ci stex_check_cmd(hba, ccb, resp); 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci if (likely(ccb->cmd != NULL)) { 9818c2ecf20Sopenharmony_ci scsi_dma_unmap(ccb->cmd); 9828c2ecf20Sopenharmony_ci stex_scsi_done(ccb); 9838c2ecf20Sopenharmony_ci } else 9848c2ecf20Sopenharmony_ci ccb->req_type = 0; 9858c2ecf20Sopenharmony_ci } 9868c2ecf20Sopenharmony_ci} 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_cistatic irqreturn_t stex_ss_intr(int irq, void *__hba) 9898c2ecf20Sopenharmony_ci{ 9908c2ecf20Sopenharmony_ci struct st_hba *hba = __hba; 9918c2ecf20Sopenharmony_ci void __iomem *base = hba->mmio_base; 9928c2ecf20Sopenharmony_ci u32 data; 9938c2ecf20Sopenharmony_ci unsigned long flags; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci spin_lock_irqsave(hba->host->host_lock, flags); 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci if (hba->cardtype == st_yel) { 9988c2ecf20Sopenharmony_ci data = readl(base + YI2H_INT); 9998c2ecf20Sopenharmony_ci if (data && data != 0xffffffff) { 10008c2ecf20Sopenharmony_ci /* clear the interrupt */ 10018c2ecf20Sopenharmony_ci writel(data, base + YI2H_INT_C); 10028c2ecf20Sopenharmony_ci stex_ss_mu_intr(hba); 10038c2ecf20Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 10048c2ecf20Sopenharmony_ci if (unlikely(data & SS_I2H_REQUEST_RESET)) 10058c2ecf20Sopenharmony_ci queue_work(hba->work_q, &hba->reset_work); 10068c2ecf20Sopenharmony_ci return IRQ_HANDLED; 10078c2ecf20Sopenharmony_ci } 10088c2ecf20Sopenharmony_ci } else { 10098c2ecf20Sopenharmony_ci data = readl(base + PSCRATCH4); 10108c2ecf20Sopenharmony_ci if (data != 0xffffffff) { 10118c2ecf20Sopenharmony_ci if (data != 0) { 10128c2ecf20Sopenharmony_ci /* clear the interrupt */ 10138c2ecf20Sopenharmony_ci writel(data, base + PSCRATCH1); 10148c2ecf20Sopenharmony_ci writel((1 << 22), base + YH2I_INT); 10158c2ecf20Sopenharmony_ci } 10168c2ecf20Sopenharmony_ci stex_ss_mu_intr(hba); 10178c2ecf20Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 10188c2ecf20Sopenharmony_ci if (unlikely(data & SS_I2H_REQUEST_RESET)) 10198c2ecf20Sopenharmony_ci queue_work(hba->work_q, &hba->reset_work); 10208c2ecf20Sopenharmony_ci return IRQ_HANDLED; 10218c2ecf20Sopenharmony_ci } 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci return IRQ_NONE; 10278c2ecf20Sopenharmony_ci} 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_cistatic int stex_common_handshake(struct st_hba *hba) 10308c2ecf20Sopenharmony_ci{ 10318c2ecf20Sopenharmony_ci void __iomem *base = hba->mmio_base; 10328c2ecf20Sopenharmony_ci struct handshake_frame *h; 10338c2ecf20Sopenharmony_ci dma_addr_t status_phys; 10348c2ecf20Sopenharmony_ci u32 data; 10358c2ecf20Sopenharmony_ci unsigned long before; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci if (readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE) { 10388c2ecf20Sopenharmony_ci writel(MU_INBOUND_DOORBELL_HANDSHAKE, base + IDBL); 10398c2ecf20Sopenharmony_ci readl(base + IDBL); 10408c2ecf20Sopenharmony_ci before = jiffies; 10418c2ecf20Sopenharmony_ci while (readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE) { 10428c2ecf20Sopenharmony_ci if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) { 10438c2ecf20Sopenharmony_ci printk(KERN_ERR DRV_NAME 10448c2ecf20Sopenharmony_ci "(%s): no handshake signature\n", 10458c2ecf20Sopenharmony_ci pci_name(hba->pdev)); 10468c2ecf20Sopenharmony_ci return -1; 10478c2ecf20Sopenharmony_ci } 10488c2ecf20Sopenharmony_ci rmb(); 10498c2ecf20Sopenharmony_ci msleep(1); 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci } 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci udelay(10); 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci data = readl(base + OMR1); 10568c2ecf20Sopenharmony_ci if ((data & 0xffff0000) == MU_HANDSHAKE_SIGNATURE_HALF) { 10578c2ecf20Sopenharmony_ci data &= 0x0000ffff; 10588c2ecf20Sopenharmony_ci if (hba->host->can_queue > data) { 10598c2ecf20Sopenharmony_ci hba->host->can_queue = data; 10608c2ecf20Sopenharmony_ci hba->host->cmd_per_lun = data; 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci } 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci h = (struct handshake_frame *)hba->status_buffer; 10658c2ecf20Sopenharmony_ci h->rb_phy = cpu_to_le64(hba->dma_handle); 10668c2ecf20Sopenharmony_ci h->req_sz = cpu_to_le16(hba->rq_size); 10678c2ecf20Sopenharmony_ci h->req_cnt = cpu_to_le16(hba->rq_count+1); 10688c2ecf20Sopenharmony_ci h->status_sz = cpu_to_le16(sizeof(struct status_msg)); 10698c2ecf20Sopenharmony_ci h->status_cnt = cpu_to_le16(hba->sts_count+1); 10708c2ecf20Sopenharmony_ci h->hosttime = cpu_to_le64(ktime_get_real_seconds()); 10718c2ecf20Sopenharmony_ci h->partner_type = HMU_PARTNER_TYPE; 10728c2ecf20Sopenharmony_ci if (hba->extra_offset) { 10738c2ecf20Sopenharmony_ci h->extra_offset = cpu_to_le32(hba->extra_offset); 10748c2ecf20Sopenharmony_ci h->extra_size = cpu_to_le32(hba->dma_size - hba->extra_offset); 10758c2ecf20Sopenharmony_ci } else 10768c2ecf20Sopenharmony_ci h->extra_offset = h->extra_size = 0; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci status_phys = hba->dma_handle + (hba->rq_count+1) * hba->rq_size; 10798c2ecf20Sopenharmony_ci writel(status_phys, base + IMR0); 10808c2ecf20Sopenharmony_ci readl(base + IMR0); 10818c2ecf20Sopenharmony_ci writel((status_phys >> 16) >> 16, base + IMR1); 10828c2ecf20Sopenharmony_ci readl(base + IMR1); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci writel((status_phys >> 16) >> 16, base + OMR0); /* old fw compatible */ 10858c2ecf20Sopenharmony_ci readl(base + OMR0); 10868c2ecf20Sopenharmony_ci writel(MU_INBOUND_DOORBELL_HANDSHAKE, base + IDBL); 10878c2ecf20Sopenharmony_ci readl(base + IDBL); /* flush */ 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci udelay(10); 10908c2ecf20Sopenharmony_ci before = jiffies; 10918c2ecf20Sopenharmony_ci while (readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE) { 10928c2ecf20Sopenharmony_ci if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) { 10938c2ecf20Sopenharmony_ci printk(KERN_ERR DRV_NAME 10948c2ecf20Sopenharmony_ci "(%s): no signature after handshake frame\n", 10958c2ecf20Sopenharmony_ci pci_name(hba->pdev)); 10968c2ecf20Sopenharmony_ci return -1; 10978c2ecf20Sopenharmony_ci } 10988c2ecf20Sopenharmony_ci rmb(); 10998c2ecf20Sopenharmony_ci msleep(1); 11008c2ecf20Sopenharmony_ci } 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci writel(0, base + IMR0); 11038c2ecf20Sopenharmony_ci readl(base + IMR0); 11048c2ecf20Sopenharmony_ci writel(0, base + OMR0); 11058c2ecf20Sopenharmony_ci readl(base + OMR0); 11068c2ecf20Sopenharmony_ci writel(0, base + IMR1); 11078c2ecf20Sopenharmony_ci readl(base + IMR1); 11088c2ecf20Sopenharmony_ci writel(0, base + OMR1); 11098c2ecf20Sopenharmony_ci readl(base + OMR1); /* flush */ 11108c2ecf20Sopenharmony_ci return 0; 11118c2ecf20Sopenharmony_ci} 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_cistatic int stex_ss_handshake(struct st_hba *hba) 11148c2ecf20Sopenharmony_ci{ 11158c2ecf20Sopenharmony_ci void __iomem *base = hba->mmio_base; 11168c2ecf20Sopenharmony_ci struct st_msg_header *msg_h; 11178c2ecf20Sopenharmony_ci struct handshake_frame *h; 11188c2ecf20Sopenharmony_ci __le32 *scratch; 11198c2ecf20Sopenharmony_ci u32 data, scratch_size, mailboxdata, operationaldata; 11208c2ecf20Sopenharmony_ci unsigned long before; 11218c2ecf20Sopenharmony_ci int ret = 0; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci before = jiffies; 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci if (hba->cardtype == st_yel) { 11268c2ecf20Sopenharmony_ci operationaldata = readl(base + YIOA_STATUS); 11278c2ecf20Sopenharmony_ci while (operationaldata != SS_MU_OPERATIONAL) { 11288c2ecf20Sopenharmony_ci if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) { 11298c2ecf20Sopenharmony_ci printk(KERN_ERR DRV_NAME 11308c2ecf20Sopenharmony_ci "(%s): firmware not operational\n", 11318c2ecf20Sopenharmony_ci pci_name(hba->pdev)); 11328c2ecf20Sopenharmony_ci return -1; 11338c2ecf20Sopenharmony_ci } 11348c2ecf20Sopenharmony_ci msleep(1); 11358c2ecf20Sopenharmony_ci operationaldata = readl(base + YIOA_STATUS); 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci } else { 11388c2ecf20Sopenharmony_ci operationaldata = readl(base + PSCRATCH3); 11398c2ecf20Sopenharmony_ci while (operationaldata != SS_MU_OPERATIONAL) { 11408c2ecf20Sopenharmony_ci if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) { 11418c2ecf20Sopenharmony_ci printk(KERN_ERR DRV_NAME 11428c2ecf20Sopenharmony_ci "(%s): firmware not operational\n", 11438c2ecf20Sopenharmony_ci pci_name(hba->pdev)); 11448c2ecf20Sopenharmony_ci return -1; 11458c2ecf20Sopenharmony_ci } 11468c2ecf20Sopenharmony_ci msleep(1); 11478c2ecf20Sopenharmony_ci operationaldata = readl(base + PSCRATCH3); 11488c2ecf20Sopenharmony_ci } 11498c2ecf20Sopenharmony_ci } 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci msg_h = (struct st_msg_header *)hba->dma_mem; 11528c2ecf20Sopenharmony_ci msg_h->handle = cpu_to_le64(hba->dma_handle); 11538c2ecf20Sopenharmony_ci msg_h->flag = SS_HEAD_HANDSHAKE; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci h = (struct handshake_frame *)(msg_h + 1); 11568c2ecf20Sopenharmony_ci h->rb_phy = cpu_to_le64(hba->dma_handle); 11578c2ecf20Sopenharmony_ci h->req_sz = cpu_to_le16(hba->rq_size); 11588c2ecf20Sopenharmony_ci h->req_cnt = cpu_to_le16(hba->rq_count+1); 11598c2ecf20Sopenharmony_ci h->status_sz = cpu_to_le16(sizeof(struct status_msg)); 11608c2ecf20Sopenharmony_ci h->status_cnt = cpu_to_le16(hba->sts_count+1); 11618c2ecf20Sopenharmony_ci h->hosttime = cpu_to_le64(ktime_get_real_seconds()); 11628c2ecf20Sopenharmony_ci h->partner_type = HMU_PARTNER_TYPE; 11638c2ecf20Sopenharmony_ci h->extra_offset = h->extra_size = 0; 11648c2ecf20Sopenharmony_ci scratch_size = (hba->sts_count+1)*sizeof(u32); 11658c2ecf20Sopenharmony_ci h->scratch_size = cpu_to_le32(scratch_size); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci if (hba->cardtype == st_yel) { 11688c2ecf20Sopenharmony_ci data = readl(base + YINT_EN); 11698c2ecf20Sopenharmony_ci data &= ~4; 11708c2ecf20Sopenharmony_ci writel(data, base + YINT_EN); 11718c2ecf20Sopenharmony_ci writel((hba->dma_handle >> 16) >> 16, base + YH2I_REQ_HI); 11728c2ecf20Sopenharmony_ci readl(base + YH2I_REQ_HI); 11738c2ecf20Sopenharmony_ci writel(hba->dma_handle, base + YH2I_REQ); 11748c2ecf20Sopenharmony_ci readl(base + YH2I_REQ); /* flush */ 11758c2ecf20Sopenharmony_ci } else { 11768c2ecf20Sopenharmony_ci data = readl(base + YINT_EN); 11778c2ecf20Sopenharmony_ci data &= ~(1 << 0); 11788c2ecf20Sopenharmony_ci data &= ~(1 << 2); 11798c2ecf20Sopenharmony_ci writel(data, base + YINT_EN); 11808c2ecf20Sopenharmony_ci if (hba->msi_lock == 0) { 11818c2ecf20Sopenharmony_ci /* P3 MSI Register cannot access twice */ 11828c2ecf20Sopenharmony_ci writel((1 << 6), base + YH2I_INT); 11838c2ecf20Sopenharmony_ci hba->msi_lock = 1; 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci writel((hba->dma_handle >> 16) >> 16, base + YH2I_REQ_HI); 11868c2ecf20Sopenharmony_ci writel(hba->dma_handle, base + YH2I_REQ); 11878c2ecf20Sopenharmony_ci } 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci before = jiffies; 11908c2ecf20Sopenharmony_ci scratch = hba->scratch; 11918c2ecf20Sopenharmony_ci if (hba->cardtype == st_yel) { 11928c2ecf20Sopenharmony_ci while (!(le32_to_cpu(*scratch) & SS_STS_HANDSHAKE)) { 11938c2ecf20Sopenharmony_ci if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) { 11948c2ecf20Sopenharmony_ci printk(KERN_ERR DRV_NAME 11958c2ecf20Sopenharmony_ci "(%s): no signature after handshake frame\n", 11968c2ecf20Sopenharmony_ci pci_name(hba->pdev)); 11978c2ecf20Sopenharmony_ci ret = -1; 11988c2ecf20Sopenharmony_ci break; 11998c2ecf20Sopenharmony_ci } 12008c2ecf20Sopenharmony_ci rmb(); 12018c2ecf20Sopenharmony_ci msleep(1); 12028c2ecf20Sopenharmony_ci } 12038c2ecf20Sopenharmony_ci } else { 12048c2ecf20Sopenharmony_ci mailboxdata = readl(base + MAILBOX_BASE + MAILBOX_HNDSHK_STS); 12058c2ecf20Sopenharmony_ci while (mailboxdata != SS_STS_HANDSHAKE) { 12068c2ecf20Sopenharmony_ci if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) { 12078c2ecf20Sopenharmony_ci printk(KERN_ERR DRV_NAME 12088c2ecf20Sopenharmony_ci "(%s): no signature after handshake frame\n", 12098c2ecf20Sopenharmony_ci pci_name(hba->pdev)); 12108c2ecf20Sopenharmony_ci ret = -1; 12118c2ecf20Sopenharmony_ci break; 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci rmb(); 12148c2ecf20Sopenharmony_ci msleep(1); 12158c2ecf20Sopenharmony_ci mailboxdata = readl(base + MAILBOX_BASE + MAILBOX_HNDSHK_STS); 12168c2ecf20Sopenharmony_ci } 12178c2ecf20Sopenharmony_ci } 12188c2ecf20Sopenharmony_ci memset(scratch, 0, scratch_size); 12198c2ecf20Sopenharmony_ci msg_h->flag = 0; 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci return ret; 12228c2ecf20Sopenharmony_ci} 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_cistatic int stex_handshake(struct st_hba *hba) 12258c2ecf20Sopenharmony_ci{ 12268c2ecf20Sopenharmony_ci int err; 12278c2ecf20Sopenharmony_ci unsigned long flags; 12288c2ecf20Sopenharmony_ci unsigned int mu_status; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci if (hba->cardtype == st_yel || hba->cardtype == st_P3) 12318c2ecf20Sopenharmony_ci err = stex_ss_handshake(hba); 12328c2ecf20Sopenharmony_ci else 12338c2ecf20Sopenharmony_ci err = stex_common_handshake(hba); 12348c2ecf20Sopenharmony_ci spin_lock_irqsave(hba->host->host_lock, flags); 12358c2ecf20Sopenharmony_ci mu_status = hba->mu_status; 12368c2ecf20Sopenharmony_ci if (err == 0) { 12378c2ecf20Sopenharmony_ci hba->req_head = 0; 12388c2ecf20Sopenharmony_ci hba->req_tail = 0; 12398c2ecf20Sopenharmony_ci hba->status_head = 0; 12408c2ecf20Sopenharmony_ci hba->status_tail = 0; 12418c2ecf20Sopenharmony_ci hba->out_req_cnt = 0; 12428c2ecf20Sopenharmony_ci hba->mu_status = MU_STATE_STARTED; 12438c2ecf20Sopenharmony_ci } else 12448c2ecf20Sopenharmony_ci hba->mu_status = MU_STATE_FAILED; 12458c2ecf20Sopenharmony_ci if (mu_status == MU_STATE_RESETTING) 12468c2ecf20Sopenharmony_ci wake_up_all(&hba->reset_waitq); 12478c2ecf20Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 12488c2ecf20Sopenharmony_ci return err; 12498c2ecf20Sopenharmony_ci} 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_cistatic int stex_abort(struct scsi_cmnd *cmd) 12528c2ecf20Sopenharmony_ci{ 12538c2ecf20Sopenharmony_ci struct Scsi_Host *host = cmd->device->host; 12548c2ecf20Sopenharmony_ci struct st_hba *hba = (struct st_hba *)host->hostdata; 12558c2ecf20Sopenharmony_ci u16 tag = cmd->request->tag; 12568c2ecf20Sopenharmony_ci void __iomem *base; 12578c2ecf20Sopenharmony_ci u32 data; 12588c2ecf20Sopenharmony_ci int result = SUCCESS; 12598c2ecf20Sopenharmony_ci unsigned long flags; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci scmd_printk(KERN_INFO, cmd, "aborting command\n"); 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci base = hba->mmio_base; 12648c2ecf20Sopenharmony_ci spin_lock_irqsave(host->host_lock, flags); 12658c2ecf20Sopenharmony_ci if (tag < host->can_queue && 12668c2ecf20Sopenharmony_ci hba->ccb[tag].req && hba->ccb[tag].cmd == cmd) 12678c2ecf20Sopenharmony_ci hba->wait_ccb = &hba->ccb[tag]; 12688c2ecf20Sopenharmony_ci else 12698c2ecf20Sopenharmony_ci goto out; 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci if (hba->cardtype == st_yel) { 12728c2ecf20Sopenharmony_ci data = readl(base + YI2H_INT); 12738c2ecf20Sopenharmony_ci if (data == 0 || data == 0xffffffff) 12748c2ecf20Sopenharmony_ci goto fail_out; 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci writel(data, base + YI2H_INT_C); 12778c2ecf20Sopenharmony_ci stex_ss_mu_intr(hba); 12788c2ecf20Sopenharmony_ci } else if (hba->cardtype == st_P3) { 12798c2ecf20Sopenharmony_ci data = readl(base + PSCRATCH4); 12808c2ecf20Sopenharmony_ci if (data == 0xffffffff) 12818c2ecf20Sopenharmony_ci goto fail_out; 12828c2ecf20Sopenharmony_ci if (data != 0) { 12838c2ecf20Sopenharmony_ci writel(data, base + PSCRATCH1); 12848c2ecf20Sopenharmony_ci writel((1 << 22), base + YH2I_INT); 12858c2ecf20Sopenharmony_ci } 12868c2ecf20Sopenharmony_ci stex_ss_mu_intr(hba); 12878c2ecf20Sopenharmony_ci } else { 12888c2ecf20Sopenharmony_ci data = readl(base + ODBL); 12898c2ecf20Sopenharmony_ci if (data == 0 || data == 0xffffffff) 12908c2ecf20Sopenharmony_ci goto fail_out; 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci writel(data, base + ODBL); 12938c2ecf20Sopenharmony_ci readl(base + ODBL); /* flush */ 12948c2ecf20Sopenharmony_ci stex_mu_intr(hba, data); 12958c2ecf20Sopenharmony_ci } 12968c2ecf20Sopenharmony_ci if (hba->wait_ccb == NULL) { 12978c2ecf20Sopenharmony_ci printk(KERN_WARNING DRV_NAME 12988c2ecf20Sopenharmony_ci "(%s): lost interrupt\n", pci_name(hba->pdev)); 12998c2ecf20Sopenharmony_ci goto out; 13008c2ecf20Sopenharmony_ci } 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_cifail_out: 13038c2ecf20Sopenharmony_ci scsi_dma_unmap(cmd); 13048c2ecf20Sopenharmony_ci hba->wait_ccb->req = NULL; /* nullify the req's future return */ 13058c2ecf20Sopenharmony_ci hba->wait_ccb = NULL; 13068c2ecf20Sopenharmony_ci result = FAILED; 13078c2ecf20Sopenharmony_ciout: 13088c2ecf20Sopenharmony_ci spin_unlock_irqrestore(host->host_lock, flags); 13098c2ecf20Sopenharmony_ci return result; 13108c2ecf20Sopenharmony_ci} 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_cistatic void stex_hard_reset(struct st_hba *hba) 13138c2ecf20Sopenharmony_ci{ 13148c2ecf20Sopenharmony_ci struct pci_bus *bus; 13158c2ecf20Sopenharmony_ci int i; 13168c2ecf20Sopenharmony_ci u16 pci_cmd; 13178c2ecf20Sopenharmony_ci u8 pci_bctl; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) 13208c2ecf20Sopenharmony_ci pci_read_config_dword(hba->pdev, i * 4, 13218c2ecf20Sopenharmony_ci &hba->pdev->saved_config_space[i]); 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci /* Reset secondary bus. Our controller(MU/ATU) is the only device on 13248c2ecf20Sopenharmony_ci secondary bus. Consult Intel 80331/3 developer's manual for detail */ 13258c2ecf20Sopenharmony_ci bus = hba->pdev->bus; 13268c2ecf20Sopenharmony_ci pci_read_config_byte(bus->self, PCI_BRIDGE_CONTROL, &pci_bctl); 13278c2ecf20Sopenharmony_ci pci_bctl |= PCI_BRIDGE_CTL_BUS_RESET; 13288c2ecf20Sopenharmony_ci pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, pci_bctl); 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci /* 13318c2ecf20Sopenharmony_ci * 1 ms may be enough for 8-port controllers. But 16-port controllers 13328c2ecf20Sopenharmony_ci * require more time to finish bus reset. Use 100 ms here for safety 13338c2ecf20Sopenharmony_ci */ 13348c2ecf20Sopenharmony_ci msleep(100); 13358c2ecf20Sopenharmony_ci pci_bctl &= ~PCI_BRIDGE_CTL_BUS_RESET; 13368c2ecf20Sopenharmony_ci pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, pci_bctl); 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci for (i = 0; i < MU_HARD_RESET_WAIT; i++) { 13398c2ecf20Sopenharmony_ci pci_read_config_word(hba->pdev, PCI_COMMAND, &pci_cmd); 13408c2ecf20Sopenharmony_ci if (pci_cmd != 0xffff && (pci_cmd & PCI_COMMAND_MASTER)) 13418c2ecf20Sopenharmony_ci break; 13428c2ecf20Sopenharmony_ci msleep(1); 13438c2ecf20Sopenharmony_ci } 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci ssleep(5); 13468c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) 13478c2ecf20Sopenharmony_ci pci_write_config_dword(hba->pdev, i * 4, 13488c2ecf20Sopenharmony_ci hba->pdev->saved_config_space[i]); 13498c2ecf20Sopenharmony_ci} 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_cistatic int stex_yos_reset(struct st_hba *hba) 13528c2ecf20Sopenharmony_ci{ 13538c2ecf20Sopenharmony_ci void __iomem *base; 13548c2ecf20Sopenharmony_ci unsigned long flags, before; 13558c2ecf20Sopenharmony_ci int ret = 0; 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci base = hba->mmio_base; 13588c2ecf20Sopenharmony_ci writel(MU_INBOUND_DOORBELL_RESET, base + IDBL); 13598c2ecf20Sopenharmony_ci readl(base + IDBL); /* flush */ 13608c2ecf20Sopenharmony_ci before = jiffies; 13618c2ecf20Sopenharmony_ci while (hba->out_req_cnt > 0) { 13628c2ecf20Sopenharmony_ci if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) { 13638c2ecf20Sopenharmony_ci printk(KERN_WARNING DRV_NAME 13648c2ecf20Sopenharmony_ci "(%s): reset timeout\n", pci_name(hba->pdev)); 13658c2ecf20Sopenharmony_ci ret = -1; 13668c2ecf20Sopenharmony_ci break; 13678c2ecf20Sopenharmony_ci } 13688c2ecf20Sopenharmony_ci msleep(1); 13698c2ecf20Sopenharmony_ci } 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci spin_lock_irqsave(hba->host->host_lock, flags); 13728c2ecf20Sopenharmony_ci if (ret == -1) 13738c2ecf20Sopenharmony_ci hba->mu_status = MU_STATE_FAILED; 13748c2ecf20Sopenharmony_ci else 13758c2ecf20Sopenharmony_ci hba->mu_status = MU_STATE_STARTED; 13768c2ecf20Sopenharmony_ci wake_up_all(&hba->reset_waitq); 13778c2ecf20Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci return ret; 13808c2ecf20Sopenharmony_ci} 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_cistatic void stex_ss_reset(struct st_hba *hba) 13838c2ecf20Sopenharmony_ci{ 13848c2ecf20Sopenharmony_ci writel(SS_H2I_INT_RESET, hba->mmio_base + YH2I_INT); 13858c2ecf20Sopenharmony_ci readl(hba->mmio_base + YH2I_INT); 13868c2ecf20Sopenharmony_ci ssleep(5); 13878c2ecf20Sopenharmony_ci} 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_cistatic void stex_p3_reset(struct st_hba *hba) 13908c2ecf20Sopenharmony_ci{ 13918c2ecf20Sopenharmony_ci writel(SS_H2I_INT_RESET, hba->mmio_base + YH2I_INT); 13928c2ecf20Sopenharmony_ci ssleep(5); 13938c2ecf20Sopenharmony_ci} 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_cistatic int stex_do_reset(struct st_hba *hba) 13968c2ecf20Sopenharmony_ci{ 13978c2ecf20Sopenharmony_ci unsigned long flags; 13988c2ecf20Sopenharmony_ci unsigned int mu_status = MU_STATE_RESETTING; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci spin_lock_irqsave(hba->host->host_lock, flags); 14018c2ecf20Sopenharmony_ci if (hba->mu_status == MU_STATE_STARTING) { 14028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 14038c2ecf20Sopenharmony_ci printk(KERN_INFO DRV_NAME "(%s): request reset during init\n", 14048c2ecf20Sopenharmony_ci pci_name(hba->pdev)); 14058c2ecf20Sopenharmony_ci return 0; 14068c2ecf20Sopenharmony_ci } 14078c2ecf20Sopenharmony_ci while (hba->mu_status == MU_STATE_RESETTING) { 14088c2ecf20Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 14098c2ecf20Sopenharmony_ci wait_event_timeout(hba->reset_waitq, 14108c2ecf20Sopenharmony_ci hba->mu_status != MU_STATE_RESETTING, 14118c2ecf20Sopenharmony_ci MU_MAX_DELAY * HZ); 14128c2ecf20Sopenharmony_ci spin_lock_irqsave(hba->host->host_lock, flags); 14138c2ecf20Sopenharmony_ci mu_status = hba->mu_status; 14148c2ecf20Sopenharmony_ci } 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci if (mu_status != MU_STATE_RESETTING) { 14178c2ecf20Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 14188c2ecf20Sopenharmony_ci return (mu_status == MU_STATE_STARTED) ? 0 : -1; 14198c2ecf20Sopenharmony_ci } 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci hba->mu_status = MU_STATE_RESETTING; 14228c2ecf20Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci if (hba->cardtype == st_yosemite) 14258c2ecf20Sopenharmony_ci return stex_yos_reset(hba); 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci if (hba->cardtype == st_shasta) 14288c2ecf20Sopenharmony_ci stex_hard_reset(hba); 14298c2ecf20Sopenharmony_ci else if (hba->cardtype == st_yel) 14308c2ecf20Sopenharmony_ci stex_ss_reset(hba); 14318c2ecf20Sopenharmony_ci else if (hba->cardtype == st_P3) 14328c2ecf20Sopenharmony_ci stex_p3_reset(hba); 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci return_abnormal_state(hba, DID_RESET); 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci if (stex_handshake(hba) == 0) 14378c2ecf20Sopenharmony_ci return 0; 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci printk(KERN_WARNING DRV_NAME "(%s): resetting: handshake failed\n", 14408c2ecf20Sopenharmony_ci pci_name(hba->pdev)); 14418c2ecf20Sopenharmony_ci return -1; 14428c2ecf20Sopenharmony_ci} 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_cistatic int stex_reset(struct scsi_cmnd *cmd) 14458c2ecf20Sopenharmony_ci{ 14468c2ecf20Sopenharmony_ci struct st_hba *hba; 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci hba = (struct st_hba *) &cmd->device->host->hostdata[0]; 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci shost_printk(KERN_INFO, cmd->device->host, 14518c2ecf20Sopenharmony_ci "resetting host\n"); 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci return stex_do_reset(hba) ? FAILED : SUCCESS; 14548c2ecf20Sopenharmony_ci} 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_cistatic void stex_reset_work(struct work_struct *work) 14578c2ecf20Sopenharmony_ci{ 14588c2ecf20Sopenharmony_ci struct st_hba *hba = container_of(work, struct st_hba, reset_work); 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci stex_do_reset(hba); 14618c2ecf20Sopenharmony_ci} 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_cistatic int stex_biosparam(struct scsi_device *sdev, 14648c2ecf20Sopenharmony_ci struct block_device *bdev, sector_t capacity, int geom[]) 14658c2ecf20Sopenharmony_ci{ 14668c2ecf20Sopenharmony_ci int heads = 255, sectors = 63; 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci if (capacity < 0x200000) { 14698c2ecf20Sopenharmony_ci heads = 64; 14708c2ecf20Sopenharmony_ci sectors = 32; 14718c2ecf20Sopenharmony_ci } 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci sector_div(capacity, heads * sectors); 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci geom[0] = heads; 14768c2ecf20Sopenharmony_ci geom[1] = sectors; 14778c2ecf20Sopenharmony_ci geom[2] = capacity; 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci return 0; 14808c2ecf20Sopenharmony_ci} 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_cistatic struct scsi_host_template driver_template = { 14838c2ecf20Sopenharmony_ci .module = THIS_MODULE, 14848c2ecf20Sopenharmony_ci .name = DRV_NAME, 14858c2ecf20Sopenharmony_ci .proc_name = DRV_NAME, 14868c2ecf20Sopenharmony_ci .bios_param = stex_biosparam, 14878c2ecf20Sopenharmony_ci .queuecommand = stex_queuecommand, 14888c2ecf20Sopenharmony_ci .slave_configure = stex_slave_config, 14898c2ecf20Sopenharmony_ci .eh_abort_handler = stex_abort, 14908c2ecf20Sopenharmony_ci .eh_host_reset_handler = stex_reset, 14918c2ecf20Sopenharmony_ci .this_id = -1, 14928c2ecf20Sopenharmony_ci .dma_boundary = PAGE_SIZE - 1, 14938c2ecf20Sopenharmony_ci}; 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_cistatic struct pci_device_id stex_pci_tbl[] = { 14968c2ecf20Sopenharmony_ci /* st_shasta */ 14978c2ecf20Sopenharmony_ci { 0x105a, 0x8350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14988c2ecf20Sopenharmony_ci st_shasta }, /* SuperTrak EX8350/8300/16350/16300 */ 14998c2ecf20Sopenharmony_ci { 0x105a, 0xc350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15008c2ecf20Sopenharmony_ci st_shasta }, /* SuperTrak EX12350 */ 15018c2ecf20Sopenharmony_ci { 0x105a, 0x4302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15028c2ecf20Sopenharmony_ci st_shasta }, /* SuperTrak EX4350 */ 15038c2ecf20Sopenharmony_ci { 0x105a, 0xe350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15048c2ecf20Sopenharmony_ci st_shasta }, /* SuperTrak EX24350 */ 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci /* st_vsc */ 15078c2ecf20Sopenharmony_ci { 0x105a, 0x7250, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_vsc }, 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci /* st_yosemite */ 15108c2ecf20Sopenharmony_ci { 0x105a, 0x8650, 0x105a, PCI_ANY_ID, 0, 0, st_yosemite }, 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci /* st_seq */ 15138c2ecf20Sopenharmony_ci { 0x105a, 0x3360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_seq }, 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci /* st_yel */ 15168c2ecf20Sopenharmony_ci { 0x105a, 0x8650, 0x1033, PCI_ANY_ID, 0, 0, st_yel }, 15178c2ecf20Sopenharmony_ci { 0x105a, 0x8760, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_yel }, 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci /* st_P3, pluto */ 15208c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_PROMISE, 0x8870, PCI_VENDOR_ID_PROMISE, 15218c2ecf20Sopenharmony_ci 0x8870, 0, 0, st_P3 }, 15228c2ecf20Sopenharmony_ci /* st_P3, p3 */ 15238c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_PROMISE, 0x8870, PCI_VENDOR_ID_PROMISE, 15248c2ecf20Sopenharmony_ci 0x4300, 0, 0, st_P3 }, 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci /* st_P3, SymplyStor4E */ 15278c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_PROMISE, 0x8871, PCI_VENDOR_ID_PROMISE, 15288c2ecf20Sopenharmony_ci 0x4311, 0, 0, st_P3 }, 15298c2ecf20Sopenharmony_ci /* st_P3, SymplyStor8E */ 15308c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_PROMISE, 0x8871, PCI_VENDOR_ID_PROMISE, 15318c2ecf20Sopenharmony_ci 0x4312, 0, 0, st_P3 }, 15328c2ecf20Sopenharmony_ci /* st_P3, SymplyStor4 */ 15338c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_PROMISE, 0x8871, PCI_VENDOR_ID_PROMISE, 15348c2ecf20Sopenharmony_ci 0x4321, 0, 0, st_P3 }, 15358c2ecf20Sopenharmony_ci /* st_P3, SymplyStor8 */ 15368c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_PROMISE, 0x8871, PCI_VENDOR_ID_PROMISE, 15378c2ecf20Sopenharmony_ci 0x4322, 0, 0, st_P3 }, 15388c2ecf20Sopenharmony_ci { } /* terminate list */ 15398c2ecf20Sopenharmony_ci}; 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_cistatic struct st_card_info stex_card_info[] = { 15428c2ecf20Sopenharmony_ci /* st_shasta */ 15438c2ecf20Sopenharmony_ci { 15448c2ecf20Sopenharmony_ci .max_id = 17, 15458c2ecf20Sopenharmony_ci .max_lun = 8, 15468c2ecf20Sopenharmony_ci .max_channel = 0, 15478c2ecf20Sopenharmony_ci .rq_count = 32, 15488c2ecf20Sopenharmony_ci .rq_size = 1048, 15498c2ecf20Sopenharmony_ci .sts_count = 32, 15508c2ecf20Sopenharmony_ci .alloc_rq = stex_alloc_req, 15518c2ecf20Sopenharmony_ci .map_sg = stex_map_sg, 15528c2ecf20Sopenharmony_ci .send = stex_send_cmd, 15538c2ecf20Sopenharmony_ci }, 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci /* st_vsc */ 15568c2ecf20Sopenharmony_ci { 15578c2ecf20Sopenharmony_ci .max_id = 129, 15588c2ecf20Sopenharmony_ci .max_lun = 1, 15598c2ecf20Sopenharmony_ci .max_channel = 0, 15608c2ecf20Sopenharmony_ci .rq_count = 32, 15618c2ecf20Sopenharmony_ci .rq_size = 1048, 15628c2ecf20Sopenharmony_ci .sts_count = 32, 15638c2ecf20Sopenharmony_ci .alloc_rq = stex_alloc_req, 15648c2ecf20Sopenharmony_ci .map_sg = stex_map_sg, 15658c2ecf20Sopenharmony_ci .send = stex_send_cmd, 15668c2ecf20Sopenharmony_ci }, 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci /* st_yosemite */ 15698c2ecf20Sopenharmony_ci { 15708c2ecf20Sopenharmony_ci .max_id = 2, 15718c2ecf20Sopenharmony_ci .max_lun = 256, 15728c2ecf20Sopenharmony_ci .max_channel = 0, 15738c2ecf20Sopenharmony_ci .rq_count = 256, 15748c2ecf20Sopenharmony_ci .rq_size = 1048, 15758c2ecf20Sopenharmony_ci .sts_count = 256, 15768c2ecf20Sopenharmony_ci .alloc_rq = stex_alloc_req, 15778c2ecf20Sopenharmony_ci .map_sg = stex_map_sg, 15788c2ecf20Sopenharmony_ci .send = stex_send_cmd, 15798c2ecf20Sopenharmony_ci }, 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci /* st_seq */ 15828c2ecf20Sopenharmony_ci { 15838c2ecf20Sopenharmony_ci .max_id = 129, 15848c2ecf20Sopenharmony_ci .max_lun = 1, 15858c2ecf20Sopenharmony_ci .max_channel = 0, 15868c2ecf20Sopenharmony_ci .rq_count = 32, 15878c2ecf20Sopenharmony_ci .rq_size = 1048, 15888c2ecf20Sopenharmony_ci .sts_count = 32, 15898c2ecf20Sopenharmony_ci .alloc_rq = stex_alloc_req, 15908c2ecf20Sopenharmony_ci .map_sg = stex_map_sg, 15918c2ecf20Sopenharmony_ci .send = stex_send_cmd, 15928c2ecf20Sopenharmony_ci }, 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci /* st_yel */ 15958c2ecf20Sopenharmony_ci { 15968c2ecf20Sopenharmony_ci .max_id = 129, 15978c2ecf20Sopenharmony_ci .max_lun = 256, 15988c2ecf20Sopenharmony_ci .max_channel = 3, 15998c2ecf20Sopenharmony_ci .rq_count = 801, 16008c2ecf20Sopenharmony_ci .rq_size = 512, 16018c2ecf20Sopenharmony_ci .sts_count = 801, 16028c2ecf20Sopenharmony_ci .alloc_rq = stex_ss_alloc_req, 16038c2ecf20Sopenharmony_ci .map_sg = stex_ss_map_sg, 16048c2ecf20Sopenharmony_ci .send = stex_ss_send_cmd, 16058c2ecf20Sopenharmony_ci }, 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci /* st_P3 */ 16088c2ecf20Sopenharmony_ci { 16098c2ecf20Sopenharmony_ci .max_id = 129, 16108c2ecf20Sopenharmony_ci .max_lun = 256, 16118c2ecf20Sopenharmony_ci .max_channel = 0, 16128c2ecf20Sopenharmony_ci .rq_count = 801, 16138c2ecf20Sopenharmony_ci .rq_size = 512, 16148c2ecf20Sopenharmony_ci .sts_count = 801, 16158c2ecf20Sopenharmony_ci .alloc_rq = stex_ss_alloc_req, 16168c2ecf20Sopenharmony_ci .map_sg = stex_ss_map_sg, 16178c2ecf20Sopenharmony_ci .send = stex_ss_send_cmd, 16188c2ecf20Sopenharmony_ci }, 16198c2ecf20Sopenharmony_ci}; 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_cistatic int stex_request_irq(struct st_hba *hba) 16228c2ecf20Sopenharmony_ci{ 16238c2ecf20Sopenharmony_ci struct pci_dev *pdev = hba->pdev; 16248c2ecf20Sopenharmony_ci int status; 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci if (msi || hba->cardtype == st_P3) { 16278c2ecf20Sopenharmony_ci status = pci_enable_msi(pdev); 16288c2ecf20Sopenharmony_ci if (status != 0) 16298c2ecf20Sopenharmony_ci printk(KERN_ERR DRV_NAME 16308c2ecf20Sopenharmony_ci "(%s): error %d setting up MSI\n", 16318c2ecf20Sopenharmony_ci pci_name(pdev), status); 16328c2ecf20Sopenharmony_ci else 16338c2ecf20Sopenharmony_ci hba->msi_enabled = 1; 16348c2ecf20Sopenharmony_ci } else 16358c2ecf20Sopenharmony_ci hba->msi_enabled = 0; 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci status = request_irq(pdev->irq, 16388c2ecf20Sopenharmony_ci (hba->cardtype == st_yel || hba->cardtype == st_P3) ? 16398c2ecf20Sopenharmony_ci stex_ss_intr : stex_intr, IRQF_SHARED, DRV_NAME, hba); 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci if (status != 0) { 16428c2ecf20Sopenharmony_ci if (hba->msi_enabled) 16438c2ecf20Sopenharmony_ci pci_disable_msi(pdev); 16448c2ecf20Sopenharmony_ci } 16458c2ecf20Sopenharmony_ci return status; 16468c2ecf20Sopenharmony_ci} 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_cistatic void stex_free_irq(struct st_hba *hba) 16498c2ecf20Sopenharmony_ci{ 16508c2ecf20Sopenharmony_ci struct pci_dev *pdev = hba->pdev; 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci free_irq(pdev->irq, hba); 16538c2ecf20Sopenharmony_ci if (hba->msi_enabled) 16548c2ecf20Sopenharmony_ci pci_disable_msi(pdev); 16558c2ecf20Sopenharmony_ci} 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_cistatic int stex_probe(struct pci_dev *pdev, const struct pci_device_id *id) 16588c2ecf20Sopenharmony_ci{ 16598c2ecf20Sopenharmony_ci struct st_hba *hba; 16608c2ecf20Sopenharmony_ci struct Scsi_Host *host; 16618c2ecf20Sopenharmony_ci const struct st_card_info *ci = NULL; 16628c2ecf20Sopenharmony_ci u32 sts_offset, cp_offset, scratch_offset; 16638c2ecf20Sopenharmony_ci int err; 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci err = pci_enable_device(pdev); 16668c2ecf20Sopenharmony_ci if (err) 16678c2ecf20Sopenharmony_ci return err; 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci pci_set_master(pdev); 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci S6flag = 0; 16728c2ecf20Sopenharmony_ci register_reboot_notifier(&stex_notifier); 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci host = scsi_host_alloc(&driver_template, sizeof(struct st_hba)); 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci if (!host) { 16778c2ecf20Sopenharmony_ci printk(KERN_ERR DRV_NAME "(%s): scsi_host_alloc failed\n", 16788c2ecf20Sopenharmony_ci pci_name(pdev)); 16798c2ecf20Sopenharmony_ci err = -ENOMEM; 16808c2ecf20Sopenharmony_ci goto out_disable; 16818c2ecf20Sopenharmony_ci } 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci hba = (struct st_hba *)host->hostdata; 16848c2ecf20Sopenharmony_ci memset(hba, 0, sizeof(struct st_hba)); 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci err = pci_request_regions(pdev, DRV_NAME); 16878c2ecf20Sopenharmony_ci if (err < 0) { 16888c2ecf20Sopenharmony_ci printk(KERN_ERR DRV_NAME "(%s): request regions failed\n", 16898c2ecf20Sopenharmony_ci pci_name(pdev)); 16908c2ecf20Sopenharmony_ci goto out_scsi_host_put; 16918c2ecf20Sopenharmony_ci } 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci hba->mmio_base = pci_ioremap_bar(pdev, 0); 16948c2ecf20Sopenharmony_ci if ( !hba->mmio_base) { 16958c2ecf20Sopenharmony_ci printk(KERN_ERR DRV_NAME "(%s): memory map failed\n", 16968c2ecf20Sopenharmony_ci pci_name(pdev)); 16978c2ecf20Sopenharmony_ci err = -ENOMEM; 16988c2ecf20Sopenharmony_ci goto out_release_regions; 16998c2ecf20Sopenharmony_ci } 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 17028c2ecf20Sopenharmony_ci if (err) 17038c2ecf20Sopenharmony_ci err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 17048c2ecf20Sopenharmony_ci if (err) { 17058c2ecf20Sopenharmony_ci printk(KERN_ERR DRV_NAME "(%s): set dma mask failed\n", 17068c2ecf20Sopenharmony_ci pci_name(pdev)); 17078c2ecf20Sopenharmony_ci goto out_iounmap; 17088c2ecf20Sopenharmony_ci } 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci hba->cardtype = (unsigned int) id->driver_data; 17118c2ecf20Sopenharmony_ci ci = &stex_card_info[hba->cardtype]; 17128c2ecf20Sopenharmony_ci switch (id->subdevice) { 17138c2ecf20Sopenharmony_ci case 0x4221: 17148c2ecf20Sopenharmony_ci case 0x4222: 17158c2ecf20Sopenharmony_ci case 0x4223: 17168c2ecf20Sopenharmony_ci case 0x4224: 17178c2ecf20Sopenharmony_ci case 0x4225: 17188c2ecf20Sopenharmony_ci case 0x4226: 17198c2ecf20Sopenharmony_ci case 0x4227: 17208c2ecf20Sopenharmony_ci case 0x4261: 17218c2ecf20Sopenharmony_ci case 0x4262: 17228c2ecf20Sopenharmony_ci case 0x4263: 17238c2ecf20Sopenharmony_ci case 0x4264: 17248c2ecf20Sopenharmony_ci case 0x4265: 17258c2ecf20Sopenharmony_ci break; 17268c2ecf20Sopenharmony_ci default: 17278c2ecf20Sopenharmony_ci if (hba->cardtype == st_yel || hba->cardtype == st_P3) 17288c2ecf20Sopenharmony_ci hba->supports_pm = 1; 17298c2ecf20Sopenharmony_ci } 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci sts_offset = scratch_offset = (ci->rq_count+1) * ci->rq_size; 17328c2ecf20Sopenharmony_ci if (hba->cardtype == st_yel || hba->cardtype == st_P3) 17338c2ecf20Sopenharmony_ci sts_offset += (ci->sts_count+1) * sizeof(u32); 17348c2ecf20Sopenharmony_ci cp_offset = sts_offset + (ci->sts_count+1) * sizeof(struct status_msg); 17358c2ecf20Sopenharmony_ci hba->dma_size = cp_offset + sizeof(struct st_frame); 17368c2ecf20Sopenharmony_ci if (hba->cardtype == st_seq || 17378c2ecf20Sopenharmony_ci (hba->cardtype == st_vsc && (pdev->subsystem_device & 1))) { 17388c2ecf20Sopenharmony_ci hba->extra_offset = hba->dma_size; 17398c2ecf20Sopenharmony_ci hba->dma_size += ST_ADDITIONAL_MEM; 17408c2ecf20Sopenharmony_ci } 17418c2ecf20Sopenharmony_ci hba->dma_mem = dma_alloc_coherent(&pdev->dev, 17428c2ecf20Sopenharmony_ci hba->dma_size, &hba->dma_handle, GFP_KERNEL); 17438c2ecf20Sopenharmony_ci if (!hba->dma_mem) { 17448c2ecf20Sopenharmony_ci /* Retry minimum coherent mapping for st_seq and st_vsc */ 17458c2ecf20Sopenharmony_ci if (hba->cardtype == st_seq || 17468c2ecf20Sopenharmony_ci (hba->cardtype == st_vsc && (pdev->subsystem_device & 1))) { 17478c2ecf20Sopenharmony_ci printk(KERN_WARNING DRV_NAME 17488c2ecf20Sopenharmony_ci "(%s): allocating min buffer for controller\n", 17498c2ecf20Sopenharmony_ci pci_name(pdev)); 17508c2ecf20Sopenharmony_ci hba->dma_size = hba->extra_offset 17518c2ecf20Sopenharmony_ci + ST_ADDITIONAL_MEM_MIN; 17528c2ecf20Sopenharmony_ci hba->dma_mem = dma_alloc_coherent(&pdev->dev, 17538c2ecf20Sopenharmony_ci hba->dma_size, &hba->dma_handle, GFP_KERNEL); 17548c2ecf20Sopenharmony_ci } 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ci if (!hba->dma_mem) { 17578c2ecf20Sopenharmony_ci err = -ENOMEM; 17588c2ecf20Sopenharmony_ci printk(KERN_ERR DRV_NAME "(%s): dma mem alloc failed\n", 17598c2ecf20Sopenharmony_ci pci_name(pdev)); 17608c2ecf20Sopenharmony_ci goto out_iounmap; 17618c2ecf20Sopenharmony_ci } 17628c2ecf20Sopenharmony_ci } 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci hba->ccb = kcalloc(ci->rq_count, sizeof(struct st_ccb), GFP_KERNEL); 17658c2ecf20Sopenharmony_ci if (!hba->ccb) { 17668c2ecf20Sopenharmony_ci err = -ENOMEM; 17678c2ecf20Sopenharmony_ci printk(KERN_ERR DRV_NAME "(%s): ccb alloc failed\n", 17688c2ecf20Sopenharmony_ci pci_name(pdev)); 17698c2ecf20Sopenharmony_ci goto out_pci_free; 17708c2ecf20Sopenharmony_ci } 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci if (hba->cardtype == st_yel || hba->cardtype == st_P3) 17738c2ecf20Sopenharmony_ci hba->scratch = (__le32 *)(hba->dma_mem + scratch_offset); 17748c2ecf20Sopenharmony_ci hba->status_buffer = (struct status_msg *)(hba->dma_mem + sts_offset); 17758c2ecf20Sopenharmony_ci hba->copy_buffer = hba->dma_mem + cp_offset; 17768c2ecf20Sopenharmony_ci hba->rq_count = ci->rq_count; 17778c2ecf20Sopenharmony_ci hba->rq_size = ci->rq_size; 17788c2ecf20Sopenharmony_ci hba->sts_count = ci->sts_count; 17798c2ecf20Sopenharmony_ci hba->alloc_rq = ci->alloc_rq; 17808c2ecf20Sopenharmony_ci hba->map_sg = ci->map_sg; 17818c2ecf20Sopenharmony_ci hba->send = ci->send; 17828c2ecf20Sopenharmony_ci hba->mu_status = MU_STATE_STARTING; 17838c2ecf20Sopenharmony_ci hba->msi_lock = 0; 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci if (hba->cardtype == st_yel || hba->cardtype == st_P3) 17868c2ecf20Sopenharmony_ci host->sg_tablesize = 38; 17878c2ecf20Sopenharmony_ci else 17888c2ecf20Sopenharmony_ci host->sg_tablesize = 32; 17898c2ecf20Sopenharmony_ci host->can_queue = ci->rq_count; 17908c2ecf20Sopenharmony_ci host->cmd_per_lun = ci->rq_count; 17918c2ecf20Sopenharmony_ci host->max_id = ci->max_id; 17928c2ecf20Sopenharmony_ci host->max_lun = ci->max_lun; 17938c2ecf20Sopenharmony_ci host->max_channel = ci->max_channel; 17948c2ecf20Sopenharmony_ci host->unique_id = host->host_no; 17958c2ecf20Sopenharmony_ci host->max_cmd_len = STEX_CDB_LENGTH; 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci hba->host = host; 17988c2ecf20Sopenharmony_ci hba->pdev = pdev; 17998c2ecf20Sopenharmony_ci init_waitqueue_head(&hba->reset_waitq); 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci snprintf(hba->work_q_name, sizeof(hba->work_q_name), 18028c2ecf20Sopenharmony_ci "stex_wq_%d", host->host_no); 18038c2ecf20Sopenharmony_ci hba->work_q = create_singlethread_workqueue(hba->work_q_name); 18048c2ecf20Sopenharmony_ci if (!hba->work_q) { 18058c2ecf20Sopenharmony_ci printk(KERN_ERR DRV_NAME "(%s): create workqueue failed\n", 18068c2ecf20Sopenharmony_ci pci_name(pdev)); 18078c2ecf20Sopenharmony_ci err = -ENOMEM; 18088c2ecf20Sopenharmony_ci goto out_ccb_free; 18098c2ecf20Sopenharmony_ci } 18108c2ecf20Sopenharmony_ci INIT_WORK(&hba->reset_work, stex_reset_work); 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci err = stex_request_irq(hba); 18138c2ecf20Sopenharmony_ci if (err) { 18148c2ecf20Sopenharmony_ci printk(KERN_ERR DRV_NAME "(%s): request irq failed\n", 18158c2ecf20Sopenharmony_ci pci_name(pdev)); 18168c2ecf20Sopenharmony_ci goto out_free_wq; 18178c2ecf20Sopenharmony_ci } 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci err = stex_handshake(hba); 18208c2ecf20Sopenharmony_ci if (err) 18218c2ecf20Sopenharmony_ci goto out_free_irq; 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, hba); 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci err = scsi_add_host(host, &pdev->dev); 18268c2ecf20Sopenharmony_ci if (err) { 18278c2ecf20Sopenharmony_ci printk(KERN_ERR DRV_NAME "(%s): scsi_add_host failed\n", 18288c2ecf20Sopenharmony_ci pci_name(pdev)); 18298c2ecf20Sopenharmony_ci goto out_free_irq; 18308c2ecf20Sopenharmony_ci } 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci scsi_scan_host(host); 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci return 0; 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ciout_free_irq: 18378c2ecf20Sopenharmony_ci stex_free_irq(hba); 18388c2ecf20Sopenharmony_ciout_free_wq: 18398c2ecf20Sopenharmony_ci destroy_workqueue(hba->work_q); 18408c2ecf20Sopenharmony_ciout_ccb_free: 18418c2ecf20Sopenharmony_ci kfree(hba->ccb); 18428c2ecf20Sopenharmony_ciout_pci_free: 18438c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, hba->dma_size, 18448c2ecf20Sopenharmony_ci hba->dma_mem, hba->dma_handle); 18458c2ecf20Sopenharmony_ciout_iounmap: 18468c2ecf20Sopenharmony_ci iounmap(hba->mmio_base); 18478c2ecf20Sopenharmony_ciout_release_regions: 18488c2ecf20Sopenharmony_ci pci_release_regions(pdev); 18498c2ecf20Sopenharmony_ciout_scsi_host_put: 18508c2ecf20Sopenharmony_ci scsi_host_put(host); 18518c2ecf20Sopenharmony_ciout_disable: 18528c2ecf20Sopenharmony_ci pci_disable_device(pdev); 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci return err; 18558c2ecf20Sopenharmony_ci} 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_cistatic void stex_hba_stop(struct st_hba *hba, int st_sleep_mic) 18588c2ecf20Sopenharmony_ci{ 18598c2ecf20Sopenharmony_ci struct req_msg *req; 18608c2ecf20Sopenharmony_ci struct st_msg_header *msg_h; 18618c2ecf20Sopenharmony_ci unsigned long flags; 18628c2ecf20Sopenharmony_ci unsigned long before; 18638c2ecf20Sopenharmony_ci u16 tag = 0; 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci spin_lock_irqsave(hba->host->host_lock, flags); 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci if ((hba->cardtype == st_yel || hba->cardtype == st_P3) && 18688c2ecf20Sopenharmony_ci hba->supports_pm == 1) { 18698c2ecf20Sopenharmony_ci if (st_sleep_mic == ST_NOTHANDLED) { 18708c2ecf20Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 18718c2ecf20Sopenharmony_ci return; 18728c2ecf20Sopenharmony_ci } 18738c2ecf20Sopenharmony_ci } 18748c2ecf20Sopenharmony_ci req = hba->alloc_rq(hba); 18758c2ecf20Sopenharmony_ci if (hba->cardtype == st_yel || hba->cardtype == st_P3) { 18768c2ecf20Sopenharmony_ci msg_h = (struct st_msg_header *)req - 1; 18778c2ecf20Sopenharmony_ci memset(msg_h, 0, hba->rq_size); 18788c2ecf20Sopenharmony_ci } else 18798c2ecf20Sopenharmony_ci memset(req, 0, hba->rq_size); 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci if ((hba->cardtype == st_yosemite || hba->cardtype == st_yel 18828c2ecf20Sopenharmony_ci || hba->cardtype == st_P3) 18838c2ecf20Sopenharmony_ci && st_sleep_mic == ST_IGNORED) { 18848c2ecf20Sopenharmony_ci req->cdb[0] = MGT_CMD; 18858c2ecf20Sopenharmony_ci req->cdb[1] = MGT_CMD_SIGNATURE; 18868c2ecf20Sopenharmony_ci req->cdb[2] = CTLR_CONFIG_CMD; 18878c2ecf20Sopenharmony_ci req->cdb[3] = CTLR_SHUTDOWN; 18888c2ecf20Sopenharmony_ci } else if ((hba->cardtype == st_yel || hba->cardtype == st_P3) 18898c2ecf20Sopenharmony_ci && st_sleep_mic != ST_IGNORED) { 18908c2ecf20Sopenharmony_ci req->cdb[0] = MGT_CMD; 18918c2ecf20Sopenharmony_ci req->cdb[1] = MGT_CMD_SIGNATURE; 18928c2ecf20Sopenharmony_ci req->cdb[2] = CTLR_CONFIG_CMD; 18938c2ecf20Sopenharmony_ci req->cdb[3] = PMIC_SHUTDOWN; 18948c2ecf20Sopenharmony_ci req->cdb[4] = st_sleep_mic; 18958c2ecf20Sopenharmony_ci } else { 18968c2ecf20Sopenharmony_ci req->cdb[0] = CONTROLLER_CMD; 18978c2ecf20Sopenharmony_ci req->cdb[1] = CTLR_POWER_STATE_CHANGE; 18988c2ecf20Sopenharmony_ci req->cdb[2] = CTLR_POWER_SAVING; 18998c2ecf20Sopenharmony_ci } 19008c2ecf20Sopenharmony_ci hba->ccb[tag].cmd = NULL; 19018c2ecf20Sopenharmony_ci hba->ccb[tag].sg_count = 0; 19028c2ecf20Sopenharmony_ci hba->ccb[tag].sense_bufflen = 0; 19038c2ecf20Sopenharmony_ci hba->ccb[tag].sense_buffer = NULL; 19048c2ecf20Sopenharmony_ci hba->ccb[tag].req_type = PASSTHRU_REQ_TYPE; 19058c2ecf20Sopenharmony_ci hba->send(hba, req, tag); 19068c2ecf20Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 19078c2ecf20Sopenharmony_ci before = jiffies; 19088c2ecf20Sopenharmony_ci while (hba->ccb[tag].req_type & PASSTHRU_REQ_TYPE) { 19098c2ecf20Sopenharmony_ci if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) { 19108c2ecf20Sopenharmony_ci hba->ccb[tag].req_type = 0; 19118c2ecf20Sopenharmony_ci hba->mu_status = MU_STATE_STOP; 19128c2ecf20Sopenharmony_ci return; 19138c2ecf20Sopenharmony_ci } 19148c2ecf20Sopenharmony_ci msleep(1); 19158c2ecf20Sopenharmony_ci } 19168c2ecf20Sopenharmony_ci hba->mu_status = MU_STATE_STOP; 19178c2ecf20Sopenharmony_ci} 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_cistatic void stex_hba_free(struct st_hba *hba) 19208c2ecf20Sopenharmony_ci{ 19218c2ecf20Sopenharmony_ci stex_free_irq(hba); 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci destroy_workqueue(hba->work_q); 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci iounmap(hba->mmio_base); 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci pci_release_regions(hba->pdev); 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci kfree(hba->ccb); 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci dma_free_coherent(&hba->pdev->dev, hba->dma_size, 19328c2ecf20Sopenharmony_ci hba->dma_mem, hba->dma_handle); 19338c2ecf20Sopenharmony_ci} 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_cistatic void stex_remove(struct pci_dev *pdev) 19368c2ecf20Sopenharmony_ci{ 19378c2ecf20Sopenharmony_ci struct st_hba *hba = pci_get_drvdata(pdev); 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci hba->mu_status = MU_STATE_NOCONNECT; 19408c2ecf20Sopenharmony_ci return_abnormal_state(hba, DID_NO_CONNECT); 19418c2ecf20Sopenharmony_ci scsi_remove_host(hba->host); 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci scsi_block_requests(hba->host); 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci stex_hba_free(hba); 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci scsi_host_put(hba->host); 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci pci_disable_device(pdev); 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci unregister_reboot_notifier(&stex_notifier); 19528c2ecf20Sopenharmony_ci} 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_cistatic void stex_shutdown(struct pci_dev *pdev) 19558c2ecf20Sopenharmony_ci{ 19568c2ecf20Sopenharmony_ci struct st_hba *hba = pci_get_drvdata(pdev); 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci if (hba->supports_pm == 0) { 19598c2ecf20Sopenharmony_ci stex_hba_stop(hba, ST_IGNORED); 19608c2ecf20Sopenharmony_ci } else if (hba->supports_pm == 1 && S6flag) { 19618c2ecf20Sopenharmony_ci unregister_reboot_notifier(&stex_notifier); 19628c2ecf20Sopenharmony_ci stex_hba_stop(hba, ST_S6); 19638c2ecf20Sopenharmony_ci } else 19648c2ecf20Sopenharmony_ci stex_hba_stop(hba, ST_S5); 19658c2ecf20Sopenharmony_ci} 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_cistatic int stex_choice_sleep_mic(struct st_hba *hba, pm_message_t state) 19688c2ecf20Sopenharmony_ci{ 19698c2ecf20Sopenharmony_ci switch (state.event) { 19708c2ecf20Sopenharmony_ci case PM_EVENT_SUSPEND: 19718c2ecf20Sopenharmony_ci return ST_S3; 19728c2ecf20Sopenharmony_ci case PM_EVENT_HIBERNATE: 19738c2ecf20Sopenharmony_ci hba->msi_lock = 0; 19748c2ecf20Sopenharmony_ci return ST_S4; 19758c2ecf20Sopenharmony_ci default: 19768c2ecf20Sopenharmony_ci return ST_NOTHANDLED; 19778c2ecf20Sopenharmony_ci } 19788c2ecf20Sopenharmony_ci} 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_cistatic int stex_suspend(struct pci_dev *pdev, pm_message_t state) 19818c2ecf20Sopenharmony_ci{ 19828c2ecf20Sopenharmony_ci struct st_hba *hba = pci_get_drvdata(pdev); 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci if ((hba->cardtype == st_yel || hba->cardtype == st_P3) 19858c2ecf20Sopenharmony_ci && hba->supports_pm == 1) 19868c2ecf20Sopenharmony_ci stex_hba_stop(hba, stex_choice_sleep_mic(hba, state)); 19878c2ecf20Sopenharmony_ci else 19888c2ecf20Sopenharmony_ci stex_hba_stop(hba, ST_IGNORED); 19898c2ecf20Sopenharmony_ci return 0; 19908c2ecf20Sopenharmony_ci} 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_cistatic int stex_resume(struct pci_dev *pdev) 19938c2ecf20Sopenharmony_ci{ 19948c2ecf20Sopenharmony_ci struct st_hba *hba = pci_get_drvdata(pdev); 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci hba->mu_status = MU_STATE_STARTING; 19978c2ecf20Sopenharmony_ci stex_handshake(hba); 19988c2ecf20Sopenharmony_ci return 0; 19998c2ecf20Sopenharmony_ci} 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_cistatic int stex_halt(struct notifier_block *nb, unsigned long event, void *buf) 20028c2ecf20Sopenharmony_ci{ 20038c2ecf20Sopenharmony_ci S6flag = 1; 20048c2ecf20Sopenharmony_ci return NOTIFY_OK; 20058c2ecf20Sopenharmony_ci} 20068c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, stex_pci_tbl); 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_cistatic struct pci_driver stex_pci_driver = { 20098c2ecf20Sopenharmony_ci .name = DRV_NAME, 20108c2ecf20Sopenharmony_ci .id_table = stex_pci_tbl, 20118c2ecf20Sopenharmony_ci .probe = stex_probe, 20128c2ecf20Sopenharmony_ci .remove = stex_remove, 20138c2ecf20Sopenharmony_ci .shutdown = stex_shutdown, 20148c2ecf20Sopenharmony_ci .suspend = stex_suspend, 20158c2ecf20Sopenharmony_ci .resume = stex_resume, 20168c2ecf20Sopenharmony_ci}; 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_cistatic int __init stex_init(void) 20198c2ecf20Sopenharmony_ci{ 20208c2ecf20Sopenharmony_ci printk(KERN_INFO DRV_NAME 20218c2ecf20Sopenharmony_ci ": Promise SuperTrak EX Driver version: %s\n", 20228c2ecf20Sopenharmony_ci ST_DRIVER_VERSION); 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci return pci_register_driver(&stex_pci_driver); 20258c2ecf20Sopenharmony_ci} 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_cistatic void __exit stex_exit(void) 20288c2ecf20Sopenharmony_ci{ 20298c2ecf20Sopenharmony_ci pci_unregister_driver(&stex_pci_driver); 20308c2ecf20Sopenharmony_ci} 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_cimodule_init(stex_init); 20338c2ecf20Sopenharmony_cimodule_exit(stex_exit); 2034