1edd16368SStephen M. Cameron /* 2edd16368SStephen M. Cameron * Disk Array driver for HP Smart Array SAS controllers 3edd16368SStephen M. Cameron * Copyright 2000, 2009 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; 145339b2b14SStephen M. Cameron unsigned char *hba_inquiry_data; 146283b4a9bSStephen M. Cameron u32 driver_support; 147283b4a9bSStephen M. Cameron u32 fw_support; 148283b4a9bSStephen M. Cameron int ioaccel_support; 149283b4a9bSStephen M. Cameron int ioaccel_maxsg; 150a0c12413SStephen M. Cameron u64 last_intr_timestamp; 151a0c12413SStephen M. Cameron u32 last_heartbeat; 152a0c12413SStephen M. Cameron u64 last_heartbeat_timestamp; 153e85c5974SStephen M. Cameron u32 heartbeat_sample_interval; 154e85c5974SStephen M. Cameron atomic_t firmware_flash_in_progress; 155a0c12413SStephen M. Cameron u32 lockup_detected; 1568a98db73SStephen M. Cameron struct delayed_work monitor_ctlr_work; 1578a98db73SStephen M. Cameron int remove_in_progress; 158396883e2SStephen M. Cameron u32 fifo_recently_full; 159254f796bSMatt Gates /* Address of h->q[x] is passed to intr handler to know which queue */ 160254f796bSMatt Gates u8 q[MAX_REPLY_QUEUES]; 16175167d2cSStephen M. Cameron u32 TMFSupportFlags; /* cache what task mgmt funcs are supported. */ 16275167d2cSStephen M. Cameron #define HPSATMF_BITS_SUPPORTED (1 << 0) 16375167d2cSStephen M. Cameron #define HPSATMF_PHYS_LUN_RESET (1 << 1) 16475167d2cSStephen M. Cameron #define HPSATMF_PHYS_NEX_RESET (1 << 2) 16575167d2cSStephen M. Cameron #define HPSATMF_PHYS_TASK_ABORT (1 << 3) 16675167d2cSStephen M. Cameron #define HPSATMF_PHYS_TSET_ABORT (1 << 4) 16775167d2cSStephen M. Cameron #define HPSATMF_PHYS_CLEAR_ACA (1 << 5) 16875167d2cSStephen M. Cameron #define HPSATMF_PHYS_CLEAR_TSET (1 << 6) 16975167d2cSStephen M. Cameron #define HPSATMF_PHYS_QRY_TASK (1 << 7) 17075167d2cSStephen M. Cameron #define HPSATMF_PHYS_QRY_TSET (1 << 8) 17175167d2cSStephen M. Cameron #define HPSATMF_PHYS_QRY_ASYNC (1 << 9) 17275167d2cSStephen M. Cameron #define HPSATMF_MASK_SUPPORTED (1 << 16) 17375167d2cSStephen M. Cameron #define HPSATMF_LOG_LUN_RESET (1 << 17) 17475167d2cSStephen M. Cameron #define HPSATMF_LOG_NEX_RESET (1 << 18) 17575167d2cSStephen M. Cameron #define HPSATMF_LOG_TASK_ABORT (1 << 19) 17675167d2cSStephen M. Cameron #define HPSATMF_LOG_TSET_ABORT (1 << 20) 17775167d2cSStephen M. Cameron #define HPSATMF_LOG_CLEAR_ACA (1 << 21) 17875167d2cSStephen M. Cameron #define HPSATMF_LOG_CLEAR_TSET (1 << 22) 17975167d2cSStephen M. Cameron #define HPSATMF_LOG_QRY_TASK (1 << 23) 18075167d2cSStephen M. Cameron #define HPSATMF_LOG_QRY_TSET (1 << 24) 18175167d2cSStephen M. Cameron #define HPSATMF_LOG_QRY_ASYNC (1 << 25) 18276438d08SStephen M. Cameron u32 events; 183edd16368SStephen M. Cameron }; 184edd16368SStephen M. Cameron #define HPSA_ABORT_MSG 0 185edd16368SStephen M. Cameron #define HPSA_DEVICE_RESET_MSG 1 18664670ac8SStephen M. Cameron #define HPSA_RESET_TYPE_CONTROLLER 0x00 18764670ac8SStephen M. Cameron #define HPSA_RESET_TYPE_BUS 0x01 18864670ac8SStephen M. Cameron #define HPSA_RESET_TYPE_TARGET 0x03 18964670ac8SStephen M. Cameron #define HPSA_RESET_TYPE_LUN 0x04 190edd16368SStephen M. Cameron #define HPSA_MSG_SEND_RETRY_LIMIT 10 191516fda49SStephen M. Cameron #define HPSA_MSG_SEND_RETRY_INTERVAL_MSECS (10000) 192edd16368SStephen M. Cameron 193edd16368SStephen M. Cameron /* Maximum time in seconds driver will wait for command completions 194edd16368SStephen M. Cameron * when polling before giving up. 195edd16368SStephen M. Cameron */ 196edd16368SStephen M. Cameron #define HPSA_MAX_POLL_TIME_SECS (20) 197edd16368SStephen M. Cameron 198edd16368SStephen M. Cameron /* During SCSI error recovery, HPSA_TUR_RETRY_LIMIT defines 199edd16368SStephen M. Cameron * how many times to retry TEST UNIT READY on a device 200edd16368SStephen M. Cameron * while waiting for it to become ready before giving up. 201edd16368SStephen M. Cameron * HPSA_MAX_WAIT_INTERVAL_SECS is the max wait interval 202edd16368SStephen M. Cameron * between sending TURs while waiting for a device 203edd16368SStephen M. Cameron * to become ready. 204edd16368SStephen M. Cameron */ 205edd16368SStephen M. Cameron #define HPSA_TUR_RETRY_LIMIT (20) 206edd16368SStephen M. Cameron #define HPSA_MAX_WAIT_INTERVAL_SECS (30) 207edd16368SStephen M. Cameron 208edd16368SStephen M. Cameron /* HPSA_BOARD_READY_WAIT_SECS is how long to wait for a board 209edd16368SStephen M. Cameron * to become ready, in seconds, before giving up on it. 210edd16368SStephen M. Cameron * HPSA_BOARD_READY_POLL_INTERVAL_MSECS * is how long to wait 211edd16368SStephen M. Cameron * between polling the board to see if it is ready, in 212edd16368SStephen M. Cameron * milliseconds. HPSA_BOARD_READY_POLL_INTERVAL and 213edd16368SStephen M. Cameron * HPSA_BOARD_READY_ITERATIONS are derived from those. 214edd16368SStephen M. Cameron */ 215edd16368SStephen M. Cameron #define HPSA_BOARD_READY_WAIT_SECS (120) 2162ed7127bSStephen M. Cameron #define HPSA_BOARD_NOT_READY_WAIT_SECS (100) 217edd16368SStephen M. Cameron #define HPSA_BOARD_READY_POLL_INTERVAL_MSECS (100) 218edd16368SStephen M. Cameron #define HPSA_BOARD_READY_POLL_INTERVAL \ 219edd16368SStephen M. Cameron ((HPSA_BOARD_READY_POLL_INTERVAL_MSECS * HZ) / 1000) 220edd16368SStephen M. Cameron #define HPSA_BOARD_READY_ITERATIONS \ 221edd16368SStephen M. Cameron ((HPSA_BOARD_READY_WAIT_SECS * 1000) / \ 222edd16368SStephen M. Cameron HPSA_BOARD_READY_POLL_INTERVAL_MSECS) 223fe5389c8SStephen M. Cameron #define HPSA_BOARD_NOT_READY_ITERATIONS \ 224fe5389c8SStephen M. Cameron ((HPSA_BOARD_NOT_READY_WAIT_SECS * 1000) / \ 225fe5389c8SStephen M. Cameron HPSA_BOARD_READY_POLL_INTERVAL_MSECS) 226edd16368SStephen M. Cameron #define HPSA_POST_RESET_PAUSE_MSECS (3000) 227edd16368SStephen M. Cameron #define HPSA_POST_RESET_NOOP_RETRIES (12) 228edd16368SStephen M. Cameron 229edd16368SStephen M. Cameron /* Defining the diffent access_menthods */ 230edd16368SStephen M. Cameron /* 231edd16368SStephen M. Cameron * Memory mapped FIFO interface (SMART 53xx cards) 232edd16368SStephen M. Cameron */ 233edd16368SStephen M. Cameron #define SA5_DOORBELL 0x20 234edd16368SStephen M. Cameron #define SA5_REQUEST_PORT_OFFSET 0x40 235edd16368SStephen M. Cameron #define SA5_REPLY_INTR_MASK_OFFSET 0x34 236edd16368SStephen M. Cameron #define SA5_REPLY_PORT_OFFSET 0x44 237edd16368SStephen M. Cameron #define SA5_INTR_STATUS 0x30 238edd16368SStephen M. Cameron #define SA5_SCRATCHPAD_OFFSET 0xB0 239edd16368SStephen M. Cameron 240edd16368SStephen M. Cameron #define SA5_CTCFG_OFFSET 0xB4 241edd16368SStephen M. Cameron #define SA5_CTMEM_OFFSET 0xB8 242edd16368SStephen M. Cameron 243edd16368SStephen M. Cameron #define SA5_INTR_OFF 0x08 244edd16368SStephen M. Cameron #define SA5B_INTR_OFF 0x04 245edd16368SStephen M. Cameron #define SA5_INTR_PENDING 0x08 246edd16368SStephen M. Cameron #define SA5B_INTR_PENDING 0x04 247edd16368SStephen M. Cameron #define FIFO_EMPTY 0xffffffff 248edd16368SStephen M. Cameron #define HPSA_FIRMWARE_READY 0xffff0000 /* value in scratchpad register */ 249edd16368SStephen M. Cameron 250edd16368SStephen M. Cameron #define HPSA_ERROR_BIT 0x02 251edd16368SStephen M. Cameron 252303932fdSDon Brace /* Performant mode flags */ 253303932fdSDon Brace #define SA5_PERF_INTR_PENDING 0x04 254303932fdSDon Brace #define SA5_PERF_INTR_OFF 0x05 255303932fdSDon Brace #define SA5_OUTDB_STATUS_PERF_BIT 0x01 256303932fdSDon Brace #define SA5_OUTDB_CLEAR_PERF_BIT 0x01 257303932fdSDon Brace #define SA5_OUTDB_CLEAR 0xA0 258303932fdSDon Brace #define SA5_OUTDB_CLEAR_PERF_BIT 0x01 259303932fdSDon Brace #define SA5_OUTDB_STATUS 0x9C 260303932fdSDon Brace 261303932fdSDon Brace 262edd16368SStephen M. Cameron #define HPSA_INTR_ON 1 263edd16368SStephen M. Cameron #define HPSA_INTR_OFF 0 264b66cc250SMike Miller 265b66cc250SMike Miller /* 266b66cc250SMike Miller * Inbound Post Queue offsets for IO Accelerator Mode 2 267b66cc250SMike Miller */ 268b66cc250SMike Miller #define IOACCEL2_INBOUND_POSTQ_32 0x48 269b66cc250SMike Miller #define IOACCEL2_INBOUND_POSTQ_64_LOW 0xd0 270b66cc250SMike Miller #define IOACCEL2_INBOUND_POSTQ_64_HI 0xd4 271b66cc250SMike Miller 272edd16368SStephen M. Cameron /* 273edd16368SStephen M. Cameron Send the command to the hardware 274edd16368SStephen M. Cameron */ 275edd16368SStephen M. Cameron static void SA5_submit_command(struct ctlr_info *h, 276edd16368SStephen M. Cameron struct CommandList *c) 277edd16368SStephen M. Cameron { 278303932fdSDon Brace dev_dbg(&h->pdev->dev, "Sending %x, tag = %x\n", c->busaddr, 279303932fdSDon Brace c->Header.Tag.lower); 280edd16368SStephen M. Cameron writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); 281fec62c36SStephen M. Cameron (void) readl(h->vaddr + SA5_SCRATCHPAD_OFFSET); 282edd16368SStephen M. Cameron } 283edd16368SStephen M. Cameron 284edd16368SStephen M. Cameron /* 285edd16368SStephen M. Cameron * This card is the opposite of the other cards. 286edd16368SStephen M. Cameron * 0 turns interrupts on... 287edd16368SStephen M. Cameron * 0x08 turns them off... 288edd16368SStephen M. Cameron */ 289edd16368SStephen M. Cameron static void SA5_intr_mask(struct ctlr_info *h, unsigned long val) 290edd16368SStephen M. Cameron { 291edd16368SStephen M. Cameron if (val) { /* Turn interrupts on */ 292edd16368SStephen M. Cameron h->interrupts_enabled = 1; 293edd16368SStephen M. Cameron writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); 2948cd21da7SStephen M. Cameron (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); 295edd16368SStephen M. Cameron } else { /* Turn them off */ 296edd16368SStephen M. Cameron h->interrupts_enabled = 0; 297edd16368SStephen M. Cameron writel(SA5_INTR_OFF, 298edd16368SStephen M. Cameron h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); 2998cd21da7SStephen M. Cameron (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); 300edd16368SStephen M. Cameron } 301edd16368SStephen M. Cameron } 302303932fdSDon Brace 303303932fdSDon Brace static void SA5_performant_intr_mask(struct ctlr_info *h, unsigned long val) 304303932fdSDon Brace { 305303932fdSDon Brace if (val) { /* turn on interrupts */ 306303932fdSDon Brace h->interrupts_enabled = 1; 307303932fdSDon Brace writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); 3088cd21da7SStephen M. Cameron (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); 309303932fdSDon Brace } else { 310303932fdSDon Brace h->interrupts_enabled = 0; 311303932fdSDon Brace writel(SA5_PERF_INTR_OFF, 312303932fdSDon Brace h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); 3138cd21da7SStephen M. Cameron (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); 314303932fdSDon Brace } 315303932fdSDon Brace } 316303932fdSDon Brace 317254f796bSMatt Gates static unsigned long SA5_performant_completed(struct ctlr_info *h, u8 q) 318303932fdSDon Brace { 319254f796bSMatt Gates struct reply_pool *rq = &h->reply_queue[q]; 320e16a33adSMatt Gates unsigned long flags, register_value = FIFO_EMPTY; 321303932fdSDon Brace 3222c17d2daSStephen M. Cameron /* msi auto clears the interrupt pending bit. */ 3232c17d2daSStephen M. Cameron if (!(h->msi_vector || h->msix_vector)) { 324303932fdSDon Brace /* flush the controller write of the reply queue by reading 325303932fdSDon Brace * outbound doorbell status register. 326303932fdSDon Brace */ 327303932fdSDon Brace register_value = readl(h->vaddr + SA5_OUTDB_STATUS); 328303932fdSDon Brace writel(SA5_OUTDB_CLEAR_PERF_BIT, h->vaddr + SA5_OUTDB_CLEAR); 329303932fdSDon Brace /* Do a read in order to flush the write to the controller 330303932fdSDon Brace * (as per spec.) 331303932fdSDon Brace */ 332303932fdSDon Brace register_value = readl(h->vaddr + SA5_OUTDB_STATUS); 333303932fdSDon Brace } 334303932fdSDon Brace 335254f796bSMatt Gates if ((rq->head[rq->current_entry] & 1) == rq->wraparound) { 336254f796bSMatt Gates register_value = rq->head[rq->current_entry]; 337254f796bSMatt Gates rq->current_entry++; 338e16a33adSMatt Gates spin_lock_irqsave(&h->lock, flags); 339303932fdSDon Brace h->commands_outstanding--; 340e16a33adSMatt Gates spin_unlock_irqrestore(&h->lock, flags); 341303932fdSDon Brace } else { 342303932fdSDon Brace register_value = FIFO_EMPTY; 343303932fdSDon Brace } 344303932fdSDon Brace /* Check for wraparound */ 345254f796bSMatt Gates if (rq->current_entry == h->max_commands) { 346254f796bSMatt Gates rq->current_entry = 0; 347254f796bSMatt Gates rq->wraparound ^= 1; 348303932fdSDon Brace } 349303932fdSDon Brace return register_value; 350303932fdSDon Brace } 351303932fdSDon Brace 352edd16368SStephen M. Cameron /* 353edd16368SStephen M. Cameron * Returns true if fifo is full. 354edd16368SStephen M. Cameron * 355edd16368SStephen M. Cameron */ 356edd16368SStephen M. Cameron static unsigned long SA5_fifo_full(struct ctlr_info *h) 357edd16368SStephen M. Cameron { 358edd16368SStephen M. Cameron if (h->commands_outstanding >= h->max_commands) 359edd16368SStephen M. Cameron return 1; 360edd16368SStephen M. Cameron else 361edd16368SStephen M. Cameron return 0; 362edd16368SStephen M. Cameron 363edd16368SStephen M. Cameron } 364edd16368SStephen M. Cameron /* 365edd16368SStephen M. Cameron * returns value read from hardware. 366edd16368SStephen M. Cameron * returns FIFO_EMPTY if there is nothing to read 367edd16368SStephen M. Cameron */ 368254f796bSMatt Gates static unsigned long SA5_completed(struct ctlr_info *h, 369254f796bSMatt Gates __attribute__((unused)) u8 q) 370edd16368SStephen M. Cameron { 371edd16368SStephen M. Cameron unsigned long register_value 372edd16368SStephen M. Cameron = readl(h->vaddr + SA5_REPLY_PORT_OFFSET); 373e16a33adSMatt Gates unsigned long flags; 374edd16368SStephen M. Cameron 375e16a33adSMatt Gates if (register_value != FIFO_EMPTY) { 376e16a33adSMatt Gates spin_lock_irqsave(&h->lock, flags); 377edd16368SStephen M. Cameron h->commands_outstanding--; 378e16a33adSMatt Gates spin_unlock_irqrestore(&h->lock, flags); 379e16a33adSMatt Gates } 380edd16368SStephen M. Cameron 381edd16368SStephen M. Cameron #ifdef HPSA_DEBUG 382edd16368SStephen M. Cameron if (register_value != FIFO_EMPTY) 38384ca0be2SStephen M. Cameron dev_dbg(&h->pdev->dev, "Read %lx back from board\n", 384edd16368SStephen M. Cameron register_value); 385edd16368SStephen M. Cameron else 386f79cfec6SStephen M. Cameron dev_dbg(&h->pdev->dev, "FIFO Empty read\n"); 387edd16368SStephen M. Cameron #endif 388edd16368SStephen M. Cameron 389edd16368SStephen M. Cameron return register_value; 390edd16368SStephen M. Cameron } 391edd16368SStephen M. Cameron /* 392edd16368SStephen M. Cameron * Returns true if an interrupt is pending.. 393edd16368SStephen M. Cameron */ 394900c5440SStephen M. Cameron static bool SA5_intr_pending(struct ctlr_info *h) 395edd16368SStephen M. Cameron { 396edd16368SStephen M. Cameron unsigned long register_value = 397edd16368SStephen M. Cameron readl(h->vaddr + SA5_INTR_STATUS); 39884ca0be2SStephen M. Cameron dev_dbg(&h->pdev->dev, "intr_pending %lx\n", register_value); 399900c5440SStephen M. Cameron return register_value & SA5_INTR_PENDING; 400edd16368SStephen M. Cameron } 401edd16368SStephen M. Cameron 402303932fdSDon Brace static bool SA5_performant_intr_pending(struct ctlr_info *h) 403303932fdSDon Brace { 404303932fdSDon Brace unsigned long register_value = readl(h->vaddr + SA5_INTR_STATUS); 405303932fdSDon Brace 406303932fdSDon Brace if (!register_value) 407303932fdSDon Brace return false; 408303932fdSDon Brace 409303932fdSDon Brace if (h->msi_vector || h->msix_vector) 410303932fdSDon Brace return true; 411303932fdSDon Brace 412303932fdSDon Brace /* Read outbound doorbell to flush */ 413303932fdSDon Brace register_value = readl(h->vaddr + SA5_OUTDB_STATUS); 414303932fdSDon Brace return register_value & SA5_OUTDB_STATUS_PERF_BIT; 415303932fdSDon Brace } 416edd16368SStephen M. Cameron 417e1f7de0cSMatt Gates #define SA5_IOACCEL_MODE1_INTR_STATUS_CMP_BIT 0x100 418e1f7de0cSMatt Gates 419e1f7de0cSMatt Gates static bool SA5_ioaccel_mode1_intr_pending(struct ctlr_info *h) 420e1f7de0cSMatt Gates { 421e1f7de0cSMatt Gates unsigned long register_value = readl(h->vaddr + SA5_INTR_STATUS); 422e1f7de0cSMatt Gates 423e1f7de0cSMatt Gates return (register_value & SA5_IOACCEL_MODE1_INTR_STATUS_CMP_BIT) ? 424e1f7de0cSMatt Gates true : false; 425e1f7de0cSMatt Gates } 426e1f7de0cSMatt Gates 427e1f7de0cSMatt Gates #define IOACCEL_MODE1_REPLY_QUEUE_INDEX 0x1A0 428e1f7de0cSMatt Gates #define IOACCEL_MODE1_PRODUCER_INDEX 0x1B8 429e1f7de0cSMatt Gates #define IOACCEL_MODE1_CONSUMER_INDEX 0x1BC 430e1f7de0cSMatt Gates #define IOACCEL_MODE1_REPLY_UNUSED 0xFFFFFFFFFFFFFFFFULL 431e1f7de0cSMatt Gates 432283b4a9bSStephen M. Cameron static unsigned long SA5_ioaccel_mode1_completed(struct ctlr_info *h, u8 q) 433e1f7de0cSMatt Gates { 434e1f7de0cSMatt Gates u64 register_value; 435e1f7de0cSMatt Gates struct reply_pool *rq = &h->reply_queue[q]; 436e1f7de0cSMatt Gates unsigned long flags; 437e1f7de0cSMatt Gates 438e1f7de0cSMatt Gates BUG_ON(q >= h->nreply_queues); 439e1f7de0cSMatt Gates 440e1f7de0cSMatt Gates register_value = rq->head[rq->current_entry]; 441e1f7de0cSMatt Gates if (register_value != IOACCEL_MODE1_REPLY_UNUSED) { 442e1f7de0cSMatt Gates rq->head[rq->current_entry] = IOACCEL_MODE1_REPLY_UNUSED; 443e1f7de0cSMatt Gates if (++rq->current_entry == rq->size) 444e1f7de0cSMatt Gates rq->current_entry = 0; 445283b4a9bSStephen M. Cameron /* 446283b4a9bSStephen M. Cameron * @todo 447283b4a9bSStephen M. Cameron * 448283b4a9bSStephen M. Cameron * Don't really need to write the new index after each command, 449283b4a9bSStephen M. Cameron * but with current driver design this is easiest. 450283b4a9bSStephen M. Cameron */ 451283b4a9bSStephen M. Cameron wmb(); 452283b4a9bSStephen M. Cameron writel((q << 24) | rq->current_entry, h->vaddr + 453283b4a9bSStephen M. Cameron IOACCEL_MODE1_CONSUMER_INDEX); 454e1f7de0cSMatt Gates spin_lock_irqsave(&h->lock, flags); 455e1f7de0cSMatt Gates h->commands_outstanding--; 456e1f7de0cSMatt Gates spin_unlock_irqrestore(&h->lock, flags); 457e1f7de0cSMatt Gates } 458e1f7de0cSMatt Gates return (unsigned long) register_value; 459e1f7de0cSMatt Gates } 460e1f7de0cSMatt Gates 461edd16368SStephen M. Cameron static struct access_method SA5_access = { 462edd16368SStephen M. Cameron SA5_submit_command, 463edd16368SStephen M. Cameron SA5_intr_mask, 464edd16368SStephen M. Cameron SA5_fifo_full, 465edd16368SStephen M. Cameron SA5_intr_pending, 466edd16368SStephen M. Cameron SA5_completed, 467edd16368SStephen M. Cameron }; 468edd16368SStephen M. Cameron 469e1f7de0cSMatt Gates static struct access_method SA5_ioaccel_mode1_access = { 470e1f7de0cSMatt Gates SA5_submit_command, 471e1f7de0cSMatt Gates SA5_performant_intr_mask, 472e1f7de0cSMatt Gates SA5_fifo_full, 473e1f7de0cSMatt Gates SA5_ioaccel_mode1_intr_pending, 474e1f7de0cSMatt Gates SA5_ioaccel_mode1_completed, 475e1f7de0cSMatt Gates }; 476e1f7de0cSMatt Gates 477303932fdSDon Brace static struct access_method SA5_performant_access = { 478303932fdSDon Brace SA5_submit_command, 479303932fdSDon Brace SA5_performant_intr_mask, 480303932fdSDon Brace SA5_fifo_full, 481303932fdSDon Brace SA5_performant_intr_pending, 482303932fdSDon Brace SA5_performant_completed, 483303932fdSDon Brace }; 484303932fdSDon Brace 485edd16368SStephen M. Cameron struct board_type { 48601a02ffcSStephen M. Cameron u32 board_id; 487edd16368SStephen M. Cameron char *product_name; 488edd16368SStephen M. Cameron struct access_method *access; 489edd16368SStephen M. Cameron }; 490edd16368SStephen M. Cameron 491edd16368SStephen M. Cameron #endif /* HPSA_H */ 492edd16368SStephen M. Cameron 493