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