1edd16368SStephen M. Cameron /* 2edd16368SStephen M. Cameron * Disk Array driver for HP Smart Array SAS controllers 351c35139SScott Teel * Copyright 2000, 2014 Hewlett-Packard Development Company, L.P. 4edd16368SStephen M. Cameron * 5edd16368SStephen M. Cameron * This program is free software; you can redistribute it and/or modify 6edd16368SStephen M. Cameron * it under the terms of the GNU General Public License as published by 7edd16368SStephen M. Cameron * the Free Software Foundation; version 2 of the License. 8edd16368SStephen M. Cameron * 9edd16368SStephen M. Cameron * This program is distributed in the hope that it will be useful, 10edd16368SStephen M. Cameron * but WITHOUT ANY WARRANTY; without even the implied warranty of 11edd16368SStephen M. Cameron * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 12edd16368SStephen M. Cameron * NON INFRINGEMENT. See the GNU General Public License for more details. 13edd16368SStephen M. Cameron * 14edd16368SStephen M. Cameron * You should have received a copy of the GNU General Public License 15edd16368SStephen M. Cameron * along with this program; if not, write to the Free Software 16edd16368SStephen M. Cameron * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17edd16368SStephen M. Cameron * 18edd16368SStephen M. Cameron * Questions/Comments/Bugfixes to iss_storagedev@hp.com 19edd16368SStephen M. Cameron * 20edd16368SStephen M. Cameron */ 21edd16368SStephen M. Cameron #ifndef HPSA_H 22edd16368SStephen M. Cameron #define HPSA_H 23edd16368SStephen M. Cameron 24edd16368SStephen M. Cameron #include <scsi/scsicam.h> 25edd16368SStephen M. Cameron 26edd16368SStephen M. Cameron #define IO_OK 0 27edd16368SStephen M. Cameron #define IO_ERROR 1 28edd16368SStephen M. Cameron 29edd16368SStephen M. Cameron struct ctlr_info; 30edd16368SStephen M. Cameron 31edd16368SStephen M. Cameron struct access_method { 32edd16368SStephen M. Cameron void (*submit_command)(struct ctlr_info *h, 33edd16368SStephen M. Cameron struct CommandList *c); 34edd16368SStephen M. Cameron void (*set_intr_mask)(struct ctlr_info *h, unsigned long val); 35edd16368SStephen M. Cameron unsigned long (*fifo_full)(struct ctlr_info *h); 36900c5440SStephen M. Cameron bool (*intr_pending)(struct ctlr_info *h); 37254f796bSMatt Gates unsigned long (*command_completed)(struct ctlr_info *h, u8 q); 38edd16368SStephen M. Cameron }; 39edd16368SStephen M. Cameron 40edd16368SStephen M. Cameron struct hpsa_scsi_dev_t { 41edd16368SStephen M. Cameron int devtype; 42edd16368SStephen M. Cameron int bus, target, lun; /* as presented to the OS */ 43edd16368SStephen M. Cameron unsigned char scsi3addr[8]; /* as presented to the HW */ 44edd16368SStephen M. Cameron #define RAID_CTLR_LUNID "\0\0\0\0\0\0\0\0" 45edd16368SStephen M. Cameron unsigned char device_id[16]; /* from inquiry pg. 0x83 */ 46edd16368SStephen M. Cameron unsigned char vendor[8]; /* bytes 8-15 of inquiry data */ 47edd16368SStephen M. Cameron unsigned char model[16]; /* bytes 16-31 of inquiry data */ 48edd16368SStephen M. Cameron unsigned char raid_level; /* from inquiry page 0xC1 */ 49e1f7de0cSMatt Gates u32 ioaccel_handle; 50283b4a9bSStephen M. Cameron int offload_config; /* I/O accel RAID offload configured */ 51283b4a9bSStephen M. Cameron int offload_enabled; /* I/O accel RAID offload enabled */ 52283b4a9bSStephen M. Cameron int offload_to_mirror; /* Send next I/O accelerator RAID 53283b4a9bSStephen M. Cameron * offload request to mirror drive 54283b4a9bSStephen M. Cameron */ 55283b4a9bSStephen M. Cameron struct raid_map_data raid_map; /* I/O accelerator RAID map */ 56283b4a9bSStephen M. Cameron 57edd16368SStephen M. Cameron }; 58edd16368SStephen M. Cameron 59254f796bSMatt Gates struct reply_pool { 60254f796bSMatt Gates u64 *head; 61254f796bSMatt Gates size_t size; 62254f796bSMatt Gates u8 wraparound; 63254f796bSMatt Gates u32 current_entry; 64254f796bSMatt Gates }; 65254f796bSMatt Gates 66edd16368SStephen M. Cameron struct ctlr_info { 67edd16368SStephen M. Cameron int ctlr; 68edd16368SStephen M. Cameron char devname[8]; 69edd16368SStephen M. Cameron char *product_name; 70edd16368SStephen M. Cameron struct pci_dev *pdev; 7101a02ffcSStephen M. Cameron u32 board_id; 72edd16368SStephen M. Cameron void __iomem *vaddr; 73edd16368SStephen M. Cameron unsigned long paddr; 74edd16368SStephen M. Cameron int nr_cmds; /* Number of commands allowed on this controller */ 75edd16368SStephen M. Cameron struct CfgTable __iomem *cfgtable; 76edd16368SStephen M. Cameron int interrupts_enabled; 77edd16368SStephen M. Cameron int major; 78edd16368SStephen M. Cameron int max_commands; 79edd16368SStephen M. Cameron int commands_outstanding; 80edd16368SStephen M. Cameron int max_outstanding; /* Debug */ 81edd16368SStephen M. Cameron int usage_count; /* number of opens all all minor devices */ 82303932fdSDon Brace # define PERF_MODE_INT 0 83303932fdSDon Brace # define DOORBELL_INT 1 84edd16368SStephen M. Cameron # define SIMPLE_MODE_INT 2 85edd16368SStephen M. Cameron # define MEMQ_MODE_INT 3 86254f796bSMatt Gates unsigned int intr[MAX_REPLY_QUEUES]; 87edd16368SStephen M. Cameron unsigned int msix_vector; 88edd16368SStephen M. Cameron unsigned int msi_vector; 89a9a3a273SStephen M. Cameron int intr_mode; /* either PERF_MODE_INT or SIMPLE_MODE_INT */ 90edd16368SStephen M. Cameron struct access_method access; 91edd16368SStephen M. Cameron 92edd16368SStephen M. Cameron /* queue and queue Info */ 939e0fc764SStephen M. Cameron struct list_head reqQ; 949e0fc764SStephen M. Cameron struct list_head cmpQ; 95edd16368SStephen M. Cameron unsigned int Qdepth; 96edd16368SStephen M. Cameron unsigned int maxSG; 97edd16368SStephen M. Cameron spinlock_t lock; 9833a2ffceSStephen M. Cameron int maxsgentries; 9933a2ffceSStephen M. Cameron u8 max_cmd_sg_entries; 10033a2ffceSStephen M. Cameron int chainsize; 10133a2ffceSStephen M. Cameron struct SGDescriptor **cmd_sg_list; 102edd16368SStephen M. Cameron 103edd16368SStephen M. Cameron /* pointers to command and error info pool */ 104edd16368SStephen M. Cameron struct CommandList *cmd_pool; 105edd16368SStephen M. Cameron dma_addr_t cmd_pool_dhandle; 106e1f7de0cSMatt Gates struct io_accel1_cmd *ioaccel_cmd_pool; 107e1f7de0cSMatt Gates dma_addr_t ioaccel_cmd_pool_dhandle; 108aca9012aSStephen M. Cameron struct io_accel2_cmd *ioaccel2_cmd_pool; 109aca9012aSStephen M. Cameron dma_addr_t ioaccel2_cmd_pool_dhandle; 110edd16368SStephen M. Cameron struct ErrorInfo *errinfo_pool; 111edd16368SStephen M. Cameron dma_addr_t errinfo_pool_dhandle; 112edd16368SStephen M. Cameron unsigned long *cmd_pool_bits; 113a08a8471SStephen M. Cameron int scan_finished; 114a08a8471SStephen M. Cameron spinlock_t scan_lock; 115a08a8471SStephen M. Cameron wait_queue_head_t scan_wait_queue; 116edd16368SStephen M. Cameron 117edd16368SStephen M. Cameron struct Scsi_Host *scsi_host; 118edd16368SStephen M. Cameron spinlock_t devlock; /* to protect hba[ctlr]->dev[]; */ 119edd16368SStephen M. Cameron int ndevices; /* number of used elements in .dev[] array. */ 120cfe5badcSScott Teel struct hpsa_scsi_dev_t *dev[HPSA_MAX_DEVICES]; 121303932fdSDon Brace /* 122303932fdSDon Brace * Performant mode tables. 123303932fdSDon Brace */ 124303932fdSDon Brace u32 trans_support; 125303932fdSDon Brace u32 trans_offset; 126303932fdSDon Brace struct TransTable_struct *transtable; 127303932fdSDon Brace unsigned long transMethod; 128303932fdSDon Brace 1290390f0c0SStephen M. Cameron /* cap concurrent passthrus at some reasonable maximum */ 1300390f0c0SStephen M. Cameron #define HPSA_MAX_CONCURRENT_PASSTHRUS (20) 1310390f0c0SStephen M. Cameron spinlock_t passthru_count_lock; /* protects passthru_count */ 1320390f0c0SStephen M. Cameron int passthru_count; 1330390f0c0SStephen M. Cameron 134303932fdSDon Brace /* 135254f796bSMatt Gates * Performant mode completion buffers 136303932fdSDon Brace */ 137303932fdSDon Brace u64 *reply_pool; 138303932fdSDon Brace size_t reply_pool_size; 139254f796bSMatt Gates struct reply_pool reply_queue[MAX_REPLY_QUEUES]; 140254f796bSMatt Gates u8 nreply_queues; 141254f796bSMatt Gates dma_addr_t reply_pool_dhandle; 142303932fdSDon Brace u32 *blockFetchTable; 143e1f7de0cSMatt Gates u32 *ioaccel1_blockFetchTable; 144aca9012aSStephen M. Cameron u32 *ioaccel2_blockFetchTable; 145b9af4937SStephen M. Cameron u32 *ioaccel2_bft2_regs; 146339b2b14SStephen M. Cameron unsigned char *hba_inquiry_data; 147283b4a9bSStephen M. Cameron u32 driver_support; 148283b4a9bSStephen M. Cameron u32 fw_support; 149283b4a9bSStephen M. Cameron int ioaccel_support; 150283b4a9bSStephen M. Cameron int ioaccel_maxsg; 151a0c12413SStephen M. Cameron u64 last_intr_timestamp; 152a0c12413SStephen M. Cameron u32 last_heartbeat; 153a0c12413SStephen M. Cameron u64 last_heartbeat_timestamp; 154e85c5974SStephen M. Cameron u32 heartbeat_sample_interval; 155e85c5974SStephen M. Cameron atomic_t firmware_flash_in_progress; 156a0c12413SStephen M. Cameron u32 lockup_detected; 1578a98db73SStephen M. Cameron struct delayed_work monitor_ctlr_work; 1588a98db73SStephen M. Cameron int remove_in_progress; 159396883e2SStephen M. Cameron u32 fifo_recently_full; 160254f796bSMatt Gates /* Address of h->q[x] is passed to intr handler to know which queue */ 161254f796bSMatt Gates u8 q[MAX_REPLY_QUEUES]; 16275167d2cSStephen M. Cameron u32 TMFSupportFlags; /* cache what task mgmt funcs are supported. */ 16375167d2cSStephen M. Cameron #define HPSATMF_BITS_SUPPORTED (1 << 0) 16475167d2cSStephen M. Cameron #define HPSATMF_PHYS_LUN_RESET (1 << 1) 16575167d2cSStephen M. Cameron #define HPSATMF_PHYS_NEX_RESET (1 << 2) 16675167d2cSStephen M. Cameron #define HPSATMF_PHYS_TASK_ABORT (1 << 3) 16775167d2cSStephen M. Cameron #define HPSATMF_PHYS_TSET_ABORT (1 << 4) 16875167d2cSStephen M. Cameron #define HPSATMF_PHYS_CLEAR_ACA (1 << 5) 16975167d2cSStephen M. Cameron #define HPSATMF_PHYS_CLEAR_TSET (1 << 6) 17075167d2cSStephen M. Cameron #define HPSATMF_PHYS_QRY_TASK (1 << 7) 17175167d2cSStephen M. Cameron #define HPSATMF_PHYS_QRY_TSET (1 << 8) 17275167d2cSStephen M. Cameron #define HPSATMF_PHYS_QRY_ASYNC (1 << 9) 17375167d2cSStephen M. Cameron #define HPSATMF_MASK_SUPPORTED (1 << 16) 17475167d2cSStephen M. Cameron #define HPSATMF_LOG_LUN_RESET (1 << 17) 17575167d2cSStephen M. Cameron #define HPSATMF_LOG_NEX_RESET (1 << 18) 17675167d2cSStephen M. Cameron #define HPSATMF_LOG_TASK_ABORT (1 << 19) 17775167d2cSStephen M. Cameron #define HPSATMF_LOG_TSET_ABORT (1 << 20) 17875167d2cSStephen M. Cameron #define HPSATMF_LOG_CLEAR_ACA (1 << 21) 17975167d2cSStephen M. Cameron #define HPSATMF_LOG_CLEAR_TSET (1 << 22) 18075167d2cSStephen M. Cameron #define HPSATMF_LOG_QRY_TASK (1 << 23) 18175167d2cSStephen M. Cameron #define HPSATMF_LOG_QRY_TSET (1 << 24) 18275167d2cSStephen M. Cameron #define HPSATMF_LOG_QRY_ASYNC (1 << 25) 18376438d08SStephen M. Cameron u32 events; 184faff6ee0SStephen M. Cameron #define CTLR_STATE_CHANGE_EVENT (1 << 0) 185faff6ee0SStephen M. Cameron #define CTLR_ENCLOSURE_HOT_PLUG_EVENT (1 << 1) 186faff6ee0SStephen M. Cameron #define CTLR_STATE_CHANGE_EVENT_PHYSICAL_DRV (1 << 4) 187faff6ee0SStephen M. Cameron #define CTLR_STATE_CHANGE_EVENT_LOGICAL_DRV (1 << 5) 188faff6ee0SStephen M. Cameron #define CTLR_STATE_CHANGE_EVENT_REDUNDANT_CNTRL (1 << 6) 189faff6ee0SStephen M. Cameron #define CTLR_STATE_CHANGE_EVENT_AIO_ENABLED_DISABLED (1 << 30) 190faff6ee0SStephen M. Cameron #define CTLR_STATE_CHANGE_EVENT_AIO_CONFIG_CHANGE (1 << 31) 191faff6ee0SStephen M. Cameron 192faff6ee0SStephen M. Cameron #define RESCAN_REQUIRED_EVENT_BITS \ 193faff6ee0SStephen M. Cameron (CTLR_STATE_CHANGE_EVENT | \ 194faff6ee0SStephen M. Cameron CTLR_ENCLOSURE_HOT_PLUG_EVENT | \ 195faff6ee0SStephen M. Cameron CTLR_STATE_CHANGE_EVENT_PHYSICAL_DRV | \ 196faff6ee0SStephen M. Cameron CTLR_STATE_CHANGE_EVENT_LOGICAL_DRV | \ 197faff6ee0SStephen M. Cameron CTLR_STATE_CHANGE_EVENT_REDUNDANT_CNTRL | \ 198faff6ee0SStephen M. Cameron CTLR_STATE_CHANGE_EVENT_AIO_ENABLED_DISABLED | \ 199faff6ee0SStephen M. Cameron CTLR_STATE_CHANGE_EVENT_AIO_CONFIG_CHANGE) 200da0697bdSScott Teel int acciopath_status; 201e863d68eSScott Teel int drv_req_rescan; /* flag for driver to request rescan event */ 2022ba8bfc8SStephen M. Cameron int raid_offload_debug; 203edd16368SStephen M. Cameron }; 204edd16368SStephen M. Cameron #define HPSA_ABORT_MSG 0 205edd16368SStephen M. Cameron #define HPSA_DEVICE_RESET_MSG 1 20664670ac8SStephen M. Cameron #define HPSA_RESET_TYPE_CONTROLLER 0x00 20764670ac8SStephen M. Cameron #define HPSA_RESET_TYPE_BUS 0x01 20864670ac8SStephen M. Cameron #define HPSA_RESET_TYPE_TARGET 0x03 20964670ac8SStephen M. Cameron #define HPSA_RESET_TYPE_LUN 0x04 210edd16368SStephen M. Cameron #define HPSA_MSG_SEND_RETRY_LIMIT 10 211516fda49SStephen M. Cameron #define HPSA_MSG_SEND_RETRY_INTERVAL_MSECS (10000) 212edd16368SStephen M. Cameron 213edd16368SStephen M. Cameron /* Maximum time in seconds driver will wait for command completions 214edd16368SStephen M. Cameron * when polling before giving up. 215edd16368SStephen M. Cameron */ 216edd16368SStephen M. Cameron #define HPSA_MAX_POLL_TIME_SECS (20) 217edd16368SStephen M. Cameron 218edd16368SStephen M. Cameron /* During SCSI error recovery, HPSA_TUR_RETRY_LIMIT defines 219edd16368SStephen M. Cameron * how many times to retry TEST UNIT READY on a device 220edd16368SStephen M. Cameron * while waiting for it to become ready before giving up. 221edd16368SStephen M. Cameron * HPSA_MAX_WAIT_INTERVAL_SECS is the max wait interval 222edd16368SStephen M. Cameron * between sending TURs while waiting for a device 223edd16368SStephen M. Cameron * to become ready. 224edd16368SStephen M. Cameron */ 225edd16368SStephen M. Cameron #define HPSA_TUR_RETRY_LIMIT (20) 226edd16368SStephen M. Cameron #define HPSA_MAX_WAIT_INTERVAL_SECS (30) 227edd16368SStephen M. Cameron 228edd16368SStephen M. Cameron /* HPSA_BOARD_READY_WAIT_SECS is how long to wait for a board 229edd16368SStephen M. Cameron * to become ready, in seconds, before giving up on it. 230edd16368SStephen M. Cameron * HPSA_BOARD_READY_POLL_INTERVAL_MSECS * is how long to wait 231edd16368SStephen M. Cameron * between polling the board to see if it is ready, in 232edd16368SStephen M. Cameron * milliseconds. HPSA_BOARD_READY_POLL_INTERVAL and 233edd16368SStephen M. Cameron * HPSA_BOARD_READY_ITERATIONS are derived from those. 234edd16368SStephen M. Cameron */ 235edd16368SStephen M. Cameron #define HPSA_BOARD_READY_WAIT_SECS (120) 2362ed7127bSStephen M. Cameron #define HPSA_BOARD_NOT_READY_WAIT_SECS (100) 237edd16368SStephen M. Cameron #define HPSA_BOARD_READY_POLL_INTERVAL_MSECS (100) 238edd16368SStephen M. Cameron #define HPSA_BOARD_READY_POLL_INTERVAL \ 239edd16368SStephen M. Cameron ((HPSA_BOARD_READY_POLL_INTERVAL_MSECS * HZ) / 1000) 240edd16368SStephen M. Cameron #define HPSA_BOARD_READY_ITERATIONS \ 241edd16368SStephen M. Cameron ((HPSA_BOARD_READY_WAIT_SECS * 1000) / \ 242edd16368SStephen M. Cameron HPSA_BOARD_READY_POLL_INTERVAL_MSECS) 243fe5389c8SStephen M. Cameron #define HPSA_BOARD_NOT_READY_ITERATIONS \ 244fe5389c8SStephen M. Cameron ((HPSA_BOARD_NOT_READY_WAIT_SECS * 1000) / \ 245fe5389c8SStephen M. Cameron HPSA_BOARD_READY_POLL_INTERVAL_MSECS) 246edd16368SStephen M. Cameron #define HPSA_POST_RESET_PAUSE_MSECS (3000) 247edd16368SStephen M. Cameron #define HPSA_POST_RESET_NOOP_RETRIES (12) 248edd16368SStephen M. Cameron 249edd16368SStephen M. Cameron /* Defining the diffent access_menthods */ 250edd16368SStephen M. Cameron /* 251edd16368SStephen M. Cameron * Memory mapped FIFO interface (SMART 53xx cards) 252edd16368SStephen M. Cameron */ 253edd16368SStephen M. Cameron #define SA5_DOORBELL 0x20 254edd16368SStephen M. Cameron #define SA5_REQUEST_PORT_OFFSET 0x40 255edd16368SStephen M. Cameron #define SA5_REPLY_INTR_MASK_OFFSET 0x34 256edd16368SStephen M. Cameron #define SA5_REPLY_PORT_OFFSET 0x44 257edd16368SStephen M. Cameron #define SA5_INTR_STATUS 0x30 258edd16368SStephen M. Cameron #define SA5_SCRATCHPAD_OFFSET 0xB0 259edd16368SStephen M. Cameron 260edd16368SStephen M. Cameron #define SA5_CTCFG_OFFSET 0xB4 261edd16368SStephen M. Cameron #define SA5_CTMEM_OFFSET 0xB8 262edd16368SStephen M. Cameron 263edd16368SStephen M. Cameron #define SA5_INTR_OFF 0x08 264edd16368SStephen M. Cameron #define SA5B_INTR_OFF 0x04 265edd16368SStephen M. Cameron #define SA5_INTR_PENDING 0x08 266edd16368SStephen M. Cameron #define SA5B_INTR_PENDING 0x04 267edd16368SStephen M. Cameron #define FIFO_EMPTY 0xffffffff 268edd16368SStephen M. Cameron #define HPSA_FIRMWARE_READY 0xffff0000 /* value in scratchpad register */ 269edd16368SStephen M. Cameron 270edd16368SStephen M. Cameron #define HPSA_ERROR_BIT 0x02 271edd16368SStephen M. Cameron 272303932fdSDon Brace /* Performant mode flags */ 273303932fdSDon Brace #define SA5_PERF_INTR_PENDING 0x04 274303932fdSDon Brace #define SA5_PERF_INTR_OFF 0x05 275303932fdSDon Brace #define SA5_OUTDB_STATUS_PERF_BIT 0x01 276303932fdSDon Brace #define SA5_OUTDB_CLEAR_PERF_BIT 0x01 277303932fdSDon Brace #define SA5_OUTDB_CLEAR 0xA0 278303932fdSDon Brace #define SA5_OUTDB_CLEAR_PERF_BIT 0x01 279303932fdSDon Brace #define SA5_OUTDB_STATUS 0x9C 280303932fdSDon Brace 281303932fdSDon Brace 282edd16368SStephen M. Cameron #define HPSA_INTR_ON 1 283edd16368SStephen M. Cameron #define HPSA_INTR_OFF 0 284b66cc250SMike Miller 285b66cc250SMike Miller /* 286b66cc250SMike Miller * Inbound Post Queue offsets for IO Accelerator Mode 2 287b66cc250SMike Miller */ 288b66cc250SMike Miller #define IOACCEL2_INBOUND_POSTQ_32 0x48 289b66cc250SMike Miller #define IOACCEL2_INBOUND_POSTQ_64_LOW 0xd0 290b66cc250SMike Miller #define IOACCEL2_INBOUND_POSTQ_64_HI 0xd4 291b66cc250SMike Miller 292edd16368SStephen M. Cameron /* 293edd16368SStephen M. Cameron Send the command to the hardware 294edd16368SStephen M. Cameron */ 295edd16368SStephen M. Cameron static void SA5_submit_command(struct ctlr_info *h, 296edd16368SStephen M. Cameron struct CommandList *c) 297edd16368SStephen M. Cameron { 298303932fdSDon Brace dev_dbg(&h->pdev->dev, "Sending %x, tag = %x\n", c->busaddr, 299303932fdSDon Brace c->Header.Tag.lower); 300edd16368SStephen M. Cameron writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); 301fec62c36SStephen M. Cameron (void) readl(h->vaddr + SA5_SCRATCHPAD_OFFSET); 302edd16368SStephen M. Cameron } 303edd16368SStephen M. Cameron 304c349775eSScott Teel static void SA5_submit_command_ioaccel2(struct ctlr_info *h, 305c349775eSScott Teel struct CommandList *c) 306c349775eSScott Teel { 307c349775eSScott Teel dev_dbg(&h->pdev->dev, "Sending %x, tag = %x\n", c->busaddr, 308c349775eSScott Teel c->Header.Tag.lower); 309c349775eSScott Teel if (c->cmd_type == CMD_IOACCEL2) 310c349775eSScott Teel writel(c->busaddr, h->vaddr + IOACCEL2_INBOUND_POSTQ_32); 311c349775eSScott Teel else 312c349775eSScott Teel writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); 313c349775eSScott Teel (void) readl(h->vaddr + SA5_SCRATCHPAD_OFFSET); 314c349775eSScott Teel } 315c349775eSScott Teel 316edd16368SStephen M. Cameron /* 317edd16368SStephen M. Cameron * This card is the opposite of the other cards. 318edd16368SStephen M. Cameron * 0 turns interrupts on... 319edd16368SStephen M. Cameron * 0x08 turns them off... 320edd16368SStephen M. Cameron */ 321edd16368SStephen M. Cameron static void SA5_intr_mask(struct ctlr_info *h, unsigned long val) 322edd16368SStephen M. Cameron { 323edd16368SStephen M. Cameron if (val) { /* Turn interrupts on */ 324edd16368SStephen M. Cameron h->interrupts_enabled = 1; 325edd16368SStephen M. Cameron writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); 3268cd21da7SStephen M. Cameron (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); 327edd16368SStephen M. Cameron } else { /* Turn them off */ 328edd16368SStephen M. Cameron h->interrupts_enabled = 0; 329edd16368SStephen M. Cameron writel(SA5_INTR_OFF, 330edd16368SStephen M. Cameron h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); 3318cd21da7SStephen M. Cameron (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); 332edd16368SStephen M. Cameron } 333edd16368SStephen M. Cameron } 334303932fdSDon Brace 335303932fdSDon Brace static void SA5_performant_intr_mask(struct ctlr_info *h, unsigned long val) 336303932fdSDon Brace { 337303932fdSDon Brace if (val) { /* turn on interrupts */ 338303932fdSDon Brace h->interrupts_enabled = 1; 339303932fdSDon Brace writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); 3408cd21da7SStephen M. Cameron (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); 341303932fdSDon Brace } else { 342303932fdSDon Brace h->interrupts_enabled = 0; 343303932fdSDon Brace writel(SA5_PERF_INTR_OFF, 344303932fdSDon Brace h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); 3458cd21da7SStephen M. Cameron (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); 346303932fdSDon Brace } 347303932fdSDon Brace } 348303932fdSDon Brace 349254f796bSMatt Gates static unsigned long SA5_performant_completed(struct ctlr_info *h, u8 q) 350303932fdSDon Brace { 351254f796bSMatt Gates struct reply_pool *rq = &h->reply_queue[q]; 352e16a33adSMatt Gates unsigned long flags, register_value = FIFO_EMPTY; 353303932fdSDon Brace 3542c17d2daSStephen M. Cameron /* msi auto clears the interrupt pending bit. */ 3552c17d2daSStephen M. Cameron if (!(h->msi_vector || h->msix_vector)) { 356303932fdSDon Brace /* flush the controller write of the reply queue by reading 357303932fdSDon Brace * outbound doorbell status register. 358303932fdSDon Brace */ 359303932fdSDon Brace register_value = readl(h->vaddr + SA5_OUTDB_STATUS); 360303932fdSDon Brace writel(SA5_OUTDB_CLEAR_PERF_BIT, h->vaddr + SA5_OUTDB_CLEAR); 361303932fdSDon Brace /* Do a read in order to flush the write to the controller 362303932fdSDon Brace * (as per spec.) 363303932fdSDon Brace */ 364303932fdSDon Brace register_value = readl(h->vaddr + SA5_OUTDB_STATUS); 365303932fdSDon Brace } 366303932fdSDon Brace 367254f796bSMatt Gates if ((rq->head[rq->current_entry] & 1) == rq->wraparound) { 368254f796bSMatt Gates register_value = rq->head[rq->current_entry]; 369254f796bSMatt Gates rq->current_entry++; 370e16a33adSMatt Gates spin_lock_irqsave(&h->lock, flags); 371303932fdSDon Brace h->commands_outstanding--; 372e16a33adSMatt Gates spin_unlock_irqrestore(&h->lock, flags); 373303932fdSDon Brace } else { 374303932fdSDon Brace register_value = FIFO_EMPTY; 375303932fdSDon Brace } 376303932fdSDon Brace /* Check for wraparound */ 377254f796bSMatt Gates if (rq->current_entry == h->max_commands) { 378254f796bSMatt Gates rq->current_entry = 0; 379254f796bSMatt Gates rq->wraparound ^= 1; 380303932fdSDon Brace } 381303932fdSDon Brace return register_value; 382303932fdSDon Brace } 383303932fdSDon Brace 384edd16368SStephen M. Cameron /* 385edd16368SStephen M. Cameron * Returns true if fifo is full. 386edd16368SStephen M. Cameron * 387edd16368SStephen M. Cameron */ 388edd16368SStephen M. Cameron static unsigned long SA5_fifo_full(struct ctlr_info *h) 389edd16368SStephen M. Cameron { 390edd16368SStephen M. Cameron if (h->commands_outstanding >= h->max_commands) 391edd16368SStephen M. Cameron return 1; 392edd16368SStephen M. Cameron else 393edd16368SStephen M. Cameron return 0; 394edd16368SStephen M. Cameron 395edd16368SStephen M. Cameron } 396edd16368SStephen M. Cameron /* 397edd16368SStephen M. Cameron * returns value read from hardware. 398edd16368SStephen M. Cameron * returns FIFO_EMPTY if there is nothing to read 399edd16368SStephen M. Cameron */ 400254f796bSMatt Gates static unsigned long SA5_completed(struct ctlr_info *h, 401254f796bSMatt Gates __attribute__((unused)) u8 q) 402edd16368SStephen M. Cameron { 403edd16368SStephen M. Cameron unsigned long register_value 404edd16368SStephen M. Cameron = readl(h->vaddr + SA5_REPLY_PORT_OFFSET); 405e16a33adSMatt Gates unsigned long flags; 406edd16368SStephen M. Cameron 407e16a33adSMatt Gates if (register_value != FIFO_EMPTY) { 408e16a33adSMatt Gates spin_lock_irqsave(&h->lock, flags); 409edd16368SStephen M. Cameron h->commands_outstanding--; 410e16a33adSMatt Gates spin_unlock_irqrestore(&h->lock, flags); 411e16a33adSMatt Gates } 412edd16368SStephen M. Cameron 413edd16368SStephen M. Cameron #ifdef HPSA_DEBUG 414edd16368SStephen M. Cameron if (register_value != FIFO_EMPTY) 41584ca0be2SStephen M. Cameron dev_dbg(&h->pdev->dev, "Read %lx back from board\n", 416edd16368SStephen M. Cameron register_value); 417edd16368SStephen M. Cameron else 418f79cfec6SStephen M. Cameron dev_dbg(&h->pdev->dev, "FIFO Empty read\n"); 419edd16368SStephen M. Cameron #endif 420edd16368SStephen M. Cameron 421edd16368SStephen M. Cameron return register_value; 422edd16368SStephen M. Cameron } 423edd16368SStephen M. Cameron /* 424edd16368SStephen M. Cameron * Returns true if an interrupt is pending.. 425edd16368SStephen M. Cameron */ 426900c5440SStephen M. Cameron static bool SA5_intr_pending(struct ctlr_info *h) 427edd16368SStephen M. Cameron { 428edd16368SStephen M. Cameron unsigned long register_value = 429edd16368SStephen M. Cameron readl(h->vaddr + SA5_INTR_STATUS); 43084ca0be2SStephen M. Cameron dev_dbg(&h->pdev->dev, "intr_pending %lx\n", register_value); 431900c5440SStephen M. Cameron return register_value & SA5_INTR_PENDING; 432edd16368SStephen M. Cameron } 433edd16368SStephen M. Cameron 434303932fdSDon Brace static bool SA5_performant_intr_pending(struct ctlr_info *h) 435303932fdSDon Brace { 436303932fdSDon Brace unsigned long register_value = readl(h->vaddr + SA5_INTR_STATUS); 437303932fdSDon Brace 438303932fdSDon Brace if (!register_value) 439303932fdSDon Brace return false; 440303932fdSDon Brace 441303932fdSDon Brace if (h->msi_vector || h->msix_vector) 442303932fdSDon Brace return true; 443303932fdSDon Brace 444303932fdSDon Brace /* Read outbound doorbell to flush */ 445303932fdSDon Brace register_value = readl(h->vaddr + SA5_OUTDB_STATUS); 446303932fdSDon Brace return register_value & SA5_OUTDB_STATUS_PERF_BIT; 447303932fdSDon Brace } 448edd16368SStephen M. Cameron 449e1f7de0cSMatt Gates #define SA5_IOACCEL_MODE1_INTR_STATUS_CMP_BIT 0x100 450e1f7de0cSMatt Gates 451e1f7de0cSMatt Gates static bool SA5_ioaccel_mode1_intr_pending(struct ctlr_info *h) 452e1f7de0cSMatt Gates { 453e1f7de0cSMatt Gates unsigned long register_value = readl(h->vaddr + SA5_INTR_STATUS); 454e1f7de0cSMatt Gates 455e1f7de0cSMatt Gates return (register_value & SA5_IOACCEL_MODE1_INTR_STATUS_CMP_BIT) ? 456e1f7de0cSMatt Gates true : false; 457e1f7de0cSMatt Gates } 458e1f7de0cSMatt Gates 459e1f7de0cSMatt Gates #define IOACCEL_MODE1_REPLY_QUEUE_INDEX 0x1A0 460e1f7de0cSMatt Gates #define IOACCEL_MODE1_PRODUCER_INDEX 0x1B8 461e1f7de0cSMatt Gates #define IOACCEL_MODE1_CONSUMER_INDEX 0x1BC 462e1f7de0cSMatt Gates #define IOACCEL_MODE1_REPLY_UNUSED 0xFFFFFFFFFFFFFFFFULL 463e1f7de0cSMatt Gates 464283b4a9bSStephen M. Cameron static unsigned long SA5_ioaccel_mode1_completed(struct ctlr_info *h, u8 q) 465e1f7de0cSMatt Gates { 466e1f7de0cSMatt Gates u64 register_value; 467e1f7de0cSMatt Gates struct reply_pool *rq = &h->reply_queue[q]; 468e1f7de0cSMatt Gates unsigned long flags; 469e1f7de0cSMatt Gates 470e1f7de0cSMatt Gates BUG_ON(q >= h->nreply_queues); 471e1f7de0cSMatt Gates 472e1f7de0cSMatt Gates register_value = rq->head[rq->current_entry]; 473e1f7de0cSMatt Gates if (register_value != IOACCEL_MODE1_REPLY_UNUSED) { 474e1f7de0cSMatt Gates rq->head[rq->current_entry] = IOACCEL_MODE1_REPLY_UNUSED; 475e1f7de0cSMatt Gates if (++rq->current_entry == rq->size) 476e1f7de0cSMatt Gates rq->current_entry = 0; 477283b4a9bSStephen M. Cameron /* 478283b4a9bSStephen M. Cameron * @todo 479283b4a9bSStephen M. Cameron * 480283b4a9bSStephen M. Cameron * Don't really need to write the new index after each command, 481283b4a9bSStephen M. Cameron * but with current driver design this is easiest. 482283b4a9bSStephen M. Cameron */ 483283b4a9bSStephen M. Cameron wmb(); 484283b4a9bSStephen M. Cameron writel((q << 24) | rq->current_entry, h->vaddr + 485283b4a9bSStephen M. Cameron IOACCEL_MODE1_CONSUMER_INDEX); 486e1f7de0cSMatt Gates spin_lock_irqsave(&h->lock, flags); 487e1f7de0cSMatt Gates h->commands_outstanding--; 488e1f7de0cSMatt Gates spin_unlock_irqrestore(&h->lock, flags); 489e1f7de0cSMatt Gates } 490e1f7de0cSMatt Gates return (unsigned long) register_value; 491e1f7de0cSMatt Gates } 492e1f7de0cSMatt Gates 493edd16368SStephen M. Cameron static struct access_method SA5_access = { 494edd16368SStephen M. Cameron SA5_submit_command, 495edd16368SStephen M. Cameron SA5_intr_mask, 496edd16368SStephen M. Cameron SA5_fifo_full, 497edd16368SStephen M. Cameron SA5_intr_pending, 498edd16368SStephen M. Cameron SA5_completed, 499edd16368SStephen M. Cameron }; 500edd16368SStephen M. Cameron 501e1f7de0cSMatt Gates static struct access_method SA5_ioaccel_mode1_access = { 502e1f7de0cSMatt Gates SA5_submit_command, 503e1f7de0cSMatt Gates SA5_performant_intr_mask, 504e1f7de0cSMatt Gates SA5_fifo_full, 505e1f7de0cSMatt Gates SA5_ioaccel_mode1_intr_pending, 506e1f7de0cSMatt Gates SA5_ioaccel_mode1_completed, 507e1f7de0cSMatt Gates }; 508e1f7de0cSMatt Gates 509c349775eSScott Teel static struct access_method SA5_ioaccel_mode2_access = { 510c349775eSScott Teel SA5_submit_command_ioaccel2, 511c349775eSScott Teel SA5_performant_intr_mask, 512c349775eSScott Teel SA5_fifo_full, 513c349775eSScott Teel SA5_performant_intr_pending, 514c349775eSScott Teel SA5_performant_completed, 515c349775eSScott Teel }; 516c349775eSScott Teel 517303932fdSDon Brace static struct access_method SA5_performant_access = { 518303932fdSDon Brace SA5_submit_command, 519303932fdSDon Brace SA5_performant_intr_mask, 520303932fdSDon Brace SA5_fifo_full, 521303932fdSDon Brace SA5_performant_intr_pending, 522303932fdSDon Brace SA5_performant_completed, 523303932fdSDon Brace }; 524303932fdSDon Brace 525edd16368SStephen M. Cameron struct board_type { 52601a02ffcSStephen M. Cameron u32 board_id; 527edd16368SStephen M. Cameron char *product_name; 528edd16368SStephen M. Cameron struct access_method *access; 529edd16368SStephen M. Cameron }; 530edd16368SStephen M. Cameron 531edd16368SStephen M. Cameron #endif /* HPSA_H */ 532edd16368SStephen M. Cameron 533