189a36810SAnil Ravindranath /* 289a36810SAnil Ravindranath * pmcraid.c -- driver for PMC Sierra MaxRAID controller adapters 389a36810SAnil Ravindranath * 4729c8456SAnil Ravindranath * Written By: Anil Ravindranath<anil_ravindranath@pmc-sierra.com> 5729c8456SAnil Ravindranath * PMC-Sierra Inc 689a36810SAnil Ravindranath * 789a36810SAnil Ravindranath * Copyright (C) 2008, 2009 PMC Sierra Inc 889a36810SAnil Ravindranath * 989a36810SAnil Ravindranath * This program is free software; you can redistribute it and/or modify 1089a36810SAnil Ravindranath * it under the terms of the GNU General Public License as published by 1189a36810SAnil Ravindranath * the Free Software Foundation; either version 2 of the License, or 1289a36810SAnil Ravindranath * (at your option) any later version. 1389a36810SAnil Ravindranath * 1489a36810SAnil Ravindranath * This program is distributed in the hope that it will be useful, 1589a36810SAnil Ravindranath * but WITHOUT ANY WARRANTY; without even the implied warranty of 1689a36810SAnil Ravindranath * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1789a36810SAnil Ravindranath * GNU General Public License for more details. 1889a36810SAnil Ravindranath * 1989a36810SAnil Ravindranath * You should have received a copy of the GNU General Public License 2089a36810SAnil Ravindranath * along with this program; if not, write to the Free Software 2189a36810SAnil Ravindranath * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, 2289a36810SAnil Ravindranath * USA 2389a36810SAnil Ravindranath * 2489a36810SAnil Ravindranath */ 2589a36810SAnil Ravindranath #include <linux/fs.h> 2689a36810SAnil Ravindranath #include <linux/init.h> 2789a36810SAnil Ravindranath #include <linux/types.h> 2889a36810SAnil Ravindranath #include <linux/errno.h> 2989a36810SAnil Ravindranath #include <linux/kernel.h> 3089a36810SAnil Ravindranath #include <linux/ioport.h> 3189a36810SAnil Ravindranath #include <linux/delay.h> 3289a36810SAnil Ravindranath #include <linux/pci.h> 3389a36810SAnil Ravindranath #include <linux/wait.h> 3489a36810SAnil Ravindranath #include <linux/spinlock.h> 3589a36810SAnil Ravindranath #include <linux/sched.h> 3689a36810SAnil Ravindranath #include <linux/interrupt.h> 3789a36810SAnil Ravindranath #include <linux/blkdev.h> 3889a36810SAnil Ravindranath #include <linux/firmware.h> 3989a36810SAnil Ravindranath #include <linux/module.h> 4089a36810SAnil Ravindranath #include <linux/moduleparam.h> 4189a36810SAnil Ravindranath #include <linux/hdreg.h> 4289a36810SAnil Ravindranath #include <linux/version.h> 4389a36810SAnil Ravindranath #include <linux/io.h> 445a0e3ad6STejun Heo #include <linux/slab.h> 4589a36810SAnil Ravindranath #include <asm/irq.h> 4689a36810SAnil Ravindranath #include <asm/processor.h> 4789a36810SAnil Ravindranath #include <linux/libata.h> 4889a36810SAnil Ravindranath #include <linux/mutex.h> 4989a36810SAnil Ravindranath #include <scsi/scsi.h> 5089a36810SAnil Ravindranath #include <scsi/scsi_host.h> 5134876402SAnil Ravindranath #include <scsi/scsi_device.h> 5289a36810SAnil Ravindranath #include <scsi/scsi_tcq.h> 5389a36810SAnil Ravindranath #include <scsi/scsi_eh.h> 5489a36810SAnil Ravindranath #include <scsi/scsi_cmnd.h> 5589a36810SAnil Ravindranath #include <scsi/scsicam.h> 5689a36810SAnil Ravindranath 5789a36810SAnil Ravindranath #include "pmcraid.h" 5889a36810SAnil Ravindranath 5989a36810SAnil Ravindranath /* 6089a36810SAnil Ravindranath * Module configuration parameters 6189a36810SAnil Ravindranath */ 6289a36810SAnil Ravindranath static unsigned int pmcraid_debug_log; 6389a36810SAnil Ravindranath static unsigned int pmcraid_disable_aen; 6489a36810SAnil Ravindranath static unsigned int pmcraid_log_level = IOASC_LOG_LEVEL_MUST; 655da61410SAnil Ravindranath static unsigned int pmcraid_enable_msix; 6689a36810SAnil Ravindranath 6789a36810SAnil Ravindranath /* 6889a36810SAnil Ravindranath * Data structures to support multiple adapters by the LLD. 6989a36810SAnil Ravindranath * pmcraid_adapter_count - count of configured adapters 7089a36810SAnil Ravindranath */ 7189a36810SAnil Ravindranath static atomic_t pmcraid_adapter_count = ATOMIC_INIT(0); 7289a36810SAnil Ravindranath 7389a36810SAnil Ravindranath /* 7489a36810SAnil Ravindranath * Supporting user-level control interface through IOCTL commands. 7589a36810SAnil Ravindranath * pmcraid_major - major number to use 7689a36810SAnil Ravindranath * pmcraid_minor - minor number(s) to use 7789a36810SAnil Ravindranath */ 7889a36810SAnil Ravindranath static unsigned int pmcraid_major; 7989a36810SAnil Ravindranath static struct class *pmcraid_class; 8089a36810SAnil Ravindranath DECLARE_BITMAP(pmcraid_minor, PMCRAID_MAX_ADAPTERS); 8189a36810SAnil Ravindranath 8289a36810SAnil Ravindranath /* 8389a36810SAnil Ravindranath * Module parameters 8489a36810SAnil Ravindranath */ 85729c8456SAnil Ravindranath MODULE_AUTHOR("Anil Ravindranath<anil_ravindranath@pmc-sierra.com>"); 8689a36810SAnil Ravindranath MODULE_DESCRIPTION("PMC Sierra MaxRAID Controller Driver"); 8789a36810SAnil Ravindranath MODULE_LICENSE("GPL"); 8889a36810SAnil Ravindranath MODULE_VERSION(PMCRAID_DRIVER_VERSION); 8989a36810SAnil Ravindranath 9089a36810SAnil Ravindranath module_param_named(log_level, pmcraid_log_level, uint, (S_IRUGO | S_IWUSR)); 9189a36810SAnil Ravindranath MODULE_PARM_DESC(log_level, 9289a36810SAnil Ravindranath "Enables firmware error code logging, default :1 high-severity" 9389a36810SAnil Ravindranath " errors, 2: all errors including high-severity errors," 9489a36810SAnil Ravindranath " 0: disables logging"); 9589a36810SAnil Ravindranath 9689a36810SAnil Ravindranath module_param_named(debug, pmcraid_debug_log, uint, (S_IRUGO | S_IWUSR)); 9789a36810SAnil Ravindranath MODULE_PARM_DESC(debug, 9889a36810SAnil Ravindranath "Enable driver verbose message logging. Set 1 to enable." 9989a36810SAnil Ravindranath "(default: 0)"); 10089a36810SAnil Ravindranath 10189a36810SAnil Ravindranath module_param_named(disable_aen, pmcraid_disable_aen, uint, (S_IRUGO | S_IWUSR)); 10289a36810SAnil Ravindranath MODULE_PARM_DESC(disable_aen, 10389a36810SAnil Ravindranath "Disable driver aen notifications to apps. Set 1 to disable." 10489a36810SAnil Ravindranath "(default: 0)"); 10589a36810SAnil Ravindranath 10689a36810SAnil Ravindranath /* chip specific constants for PMC MaxRAID controllers (same for 10789a36810SAnil Ravindranath * 0x5220 and 0x8010 10889a36810SAnil Ravindranath */ 10989a36810SAnil Ravindranath static struct pmcraid_chip_details pmcraid_chip_cfg[] = { 11089a36810SAnil Ravindranath { 11189a36810SAnil Ravindranath .ioastatus = 0x0, 11289a36810SAnil Ravindranath .ioarrin = 0x00040, 11389a36810SAnil Ravindranath .mailbox = 0x7FC30, 11489a36810SAnil Ravindranath .global_intr_mask = 0x00034, 11589a36810SAnil Ravindranath .ioa_host_intr = 0x0009C, 11689a36810SAnil Ravindranath .ioa_host_intr_clr = 0x000A0, 117c20c4267SAnil Ravindranath .ioa_host_msix_intr = 0x7FC40, 11889a36810SAnil Ravindranath .ioa_host_mask = 0x7FC28, 11989a36810SAnil Ravindranath .ioa_host_mask_clr = 0x7FC28, 12089a36810SAnil Ravindranath .host_ioa_intr = 0x00020, 12189a36810SAnil Ravindranath .host_ioa_intr_clr = 0x00020, 12289a36810SAnil Ravindranath .transop_timeout = 300 12389a36810SAnil Ravindranath } 12489a36810SAnil Ravindranath }; 12589a36810SAnil Ravindranath 12689a36810SAnil Ravindranath /* 12789a36810SAnil Ravindranath * PCI device ids supported by pmcraid driver 12889a36810SAnil Ravindranath */ 12989a36810SAnil Ravindranath static struct pci_device_id pmcraid_pci_table[] __devinitdata = { 13089a36810SAnil Ravindranath { PCI_DEVICE(PCI_VENDOR_ID_PMC, PCI_DEVICE_ID_PMC_MAXRAID), 13189a36810SAnil Ravindranath 0, 0, (kernel_ulong_t)&pmcraid_chip_cfg[0] 13289a36810SAnil Ravindranath }, 13389a36810SAnil Ravindranath {} 13489a36810SAnil Ravindranath }; 13589a36810SAnil Ravindranath 13689a36810SAnil Ravindranath MODULE_DEVICE_TABLE(pci, pmcraid_pci_table); 13789a36810SAnil Ravindranath 13889a36810SAnil Ravindranath 13989a36810SAnil Ravindranath 14089a36810SAnil Ravindranath /** 14189a36810SAnil Ravindranath * pmcraid_slave_alloc - Prepare for commands to a device 14289a36810SAnil Ravindranath * @scsi_dev: scsi device struct 14389a36810SAnil Ravindranath * 14489a36810SAnil Ravindranath * This function is called by mid-layer prior to sending any command to the new 14589a36810SAnil Ravindranath * device. Stores resource entry details of the device in scsi_device struct. 14689a36810SAnil Ravindranath * Queuecommand uses the resource handle and other details to fill up IOARCB 14789a36810SAnil Ravindranath * while sending commands to the device. 14889a36810SAnil Ravindranath * 14989a36810SAnil Ravindranath * Return value: 15089a36810SAnil Ravindranath * 0 on success / -ENXIO if device does not exist 15189a36810SAnil Ravindranath */ 15289a36810SAnil Ravindranath static int pmcraid_slave_alloc(struct scsi_device *scsi_dev) 15389a36810SAnil Ravindranath { 15489a36810SAnil Ravindranath struct pmcraid_resource_entry *temp, *res = NULL; 15589a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 15689a36810SAnil Ravindranath u8 target, bus, lun; 15789a36810SAnil Ravindranath unsigned long lock_flags; 15889a36810SAnil Ravindranath int rc = -ENXIO; 159c20c4267SAnil Ravindranath u16 fw_version; 160c20c4267SAnil Ravindranath 16189a36810SAnil Ravindranath pinstance = shost_priv(scsi_dev->host); 16289a36810SAnil Ravindranath 163c20c4267SAnil Ravindranath fw_version = be16_to_cpu(pinstance->inq_data->fw_version); 164c20c4267SAnil Ravindranath 16589a36810SAnil Ravindranath /* Driver exposes VSET and GSCSI resources only; all other device types 16689a36810SAnil Ravindranath * are not exposed. Resource list is synchronized using resource lock 16789a36810SAnil Ravindranath * so any traversal or modifications to the list should be done inside 16889a36810SAnil Ravindranath * this lock 16989a36810SAnil Ravindranath */ 17089a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->resource_lock, lock_flags); 17189a36810SAnil Ravindranath list_for_each_entry(temp, &pinstance->used_res_q, queue) { 17289a36810SAnil Ravindranath 173729c8456SAnil Ravindranath /* do not expose VSETs with order-ids > MAX_VSET_TARGETS */ 17489a36810SAnil Ravindranath if (RES_IS_VSET(temp->cfg_entry)) { 175c20c4267SAnil Ravindranath if (fw_version <= PMCRAID_FW_VERSION_1) 17689a36810SAnil Ravindranath target = temp->cfg_entry.unique_flags1; 177c20c4267SAnil Ravindranath else 178c20c4267SAnil Ravindranath target = temp->cfg_entry.array_id & 0xFF; 179c20c4267SAnil Ravindranath 180729c8456SAnil Ravindranath if (target > PMCRAID_MAX_VSET_TARGETS) 18189a36810SAnil Ravindranath continue; 18289a36810SAnil Ravindranath bus = PMCRAID_VSET_BUS_ID; 18389a36810SAnil Ravindranath lun = 0; 18489a36810SAnil Ravindranath } else if (RES_IS_GSCSI(temp->cfg_entry)) { 18589a36810SAnil Ravindranath target = RES_TARGET(temp->cfg_entry.resource_address); 18689a36810SAnil Ravindranath bus = PMCRAID_PHYS_BUS_ID; 18789a36810SAnil Ravindranath lun = RES_LUN(temp->cfg_entry.resource_address); 18889a36810SAnil Ravindranath } else { 18989a36810SAnil Ravindranath continue; 19089a36810SAnil Ravindranath } 19189a36810SAnil Ravindranath 19289a36810SAnil Ravindranath if (bus == scsi_dev->channel && 19389a36810SAnil Ravindranath target == scsi_dev->id && 19489a36810SAnil Ravindranath lun == scsi_dev->lun) { 19589a36810SAnil Ravindranath res = temp; 19689a36810SAnil Ravindranath break; 19789a36810SAnil Ravindranath } 19889a36810SAnil Ravindranath } 19989a36810SAnil Ravindranath 20089a36810SAnil Ravindranath if (res) { 20189a36810SAnil Ravindranath res->scsi_dev = scsi_dev; 20289a36810SAnil Ravindranath scsi_dev->hostdata = res; 20389a36810SAnil Ravindranath res->change_detected = 0; 20489a36810SAnil Ravindranath atomic_set(&res->read_failures, 0); 20589a36810SAnil Ravindranath atomic_set(&res->write_failures, 0); 20689a36810SAnil Ravindranath rc = 0; 20789a36810SAnil Ravindranath } 20889a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); 20989a36810SAnil Ravindranath return rc; 21089a36810SAnil Ravindranath } 21189a36810SAnil Ravindranath 21289a36810SAnil Ravindranath /** 21389a36810SAnil Ravindranath * pmcraid_slave_configure - Configures a SCSI device 21489a36810SAnil Ravindranath * @scsi_dev: scsi device struct 21589a36810SAnil Ravindranath * 21625985edcSLucas De Marchi * This function is executed by SCSI mid layer just after a device is first 21789a36810SAnil Ravindranath * scanned (i.e. it has responded to an INQUIRY). For VSET resources, the 21889a36810SAnil Ravindranath * timeout value (default 30s) will be over-written to a higher value (60s) 21989a36810SAnil Ravindranath * and max_sectors value will be over-written to 512. It also sets queue depth 22089a36810SAnil Ravindranath * to host->cmd_per_lun value 22189a36810SAnil Ravindranath * 22289a36810SAnil Ravindranath * Return value: 22389a36810SAnil Ravindranath * 0 on success 22489a36810SAnil Ravindranath */ 22589a36810SAnil Ravindranath static int pmcraid_slave_configure(struct scsi_device *scsi_dev) 22689a36810SAnil Ravindranath { 22789a36810SAnil Ravindranath struct pmcraid_resource_entry *res = scsi_dev->hostdata; 22889a36810SAnil Ravindranath 22989a36810SAnil Ravindranath if (!res) 23089a36810SAnil Ravindranath return 0; 23189a36810SAnil Ravindranath 23289a36810SAnil Ravindranath /* LLD exposes VSETs and Enclosure devices only */ 23389a36810SAnil Ravindranath if (RES_IS_GSCSI(res->cfg_entry) && 23489a36810SAnil Ravindranath scsi_dev->type != TYPE_ENCLOSURE) 23589a36810SAnil Ravindranath return -ENXIO; 23689a36810SAnil Ravindranath 23789a36810SAnil Ravindranath pmcraid_info("configuring %x:%x:%x:%x\n", 23889a36810SAnil Ravindranath scsi_dev->host->unique_id, 23989a36810SAnil Ravindranath scsi_dev->channel, 24089a36810SAnil Ravindranath scsi_dev->id, 24189a36810SAnil Ravindranath scsi_dev->lun); 24289a36810SAnil Ravindranath 24389a36810SAnil Ravindranath if (RES_IS_GSCSI(res->cfg_entry)) { 24489a36810SAnil Ravindranath scsi_dev->allow_restart = 1; 24589a36810SAnil Ravindranath } else if (RES_IS_VSET(res->cfg_entry)) { 24689a36810SAnil Ravindranath scsi_dev->allow_restart = 1; 24789a36810SAnil Ravindranath blk_queue_rq_timeout(scsi_dev->request_queue, 24889a36810SAnil Ravindranath PMCRAID_VSET_IO_TIMEOUT); 249086fa5ffSMartin K. Petersen blk_queue_max_hw_sectors(scsi_dev->request_queue, 25089a36810SAnil Ravindranath PMCRAID_VSET_MAX_SECTORS); 25189a36810SAnil Ravindranath } 25289a36810SAnil Ravindranath 25389a36810SAnil Ravindranath if (scsi_dev->tagged_supported && 25489a36810SAnil Ravindranath (RES_IS_GSCSI(res->cfg_entry) || RES_IS_VSET(res->cfg_entry))) { 25589a36810SAnil Ravindranath scsi_activate_tcq(scsi_dev, scsi_dev->queue_depth); 25689a36810SAnil Ravindranath scsi_adjust_queue_depth(scsi_dev, MSG_SIMPLE_TAG, 25789a36810SAnil Ravindranath scsi_dev->host->cmd_per_lun); 25889a36810SAnil Ravindranath } else { 25989a36810SAnil Ravindranath scsi_adjust_queue_depth(scsi_dev, 0, 26089a36810SAnil Ravindranath scsi_dev->host->cmd_per_lun); 26189a36810SAnil Ravindranath } 26289a36810SAnil Ravindranath 26389a36810SAnil Ravindranath return 0; 26489a36810SAnil Ravindranath } 26589a36810SAnil Ravindranath 26689a36810SAnil Ravindranath /** 26789a36810SAnil Ravindranath * pmcraid_slave_destroy - Unconfigure a SCSI device before removing it 26889a36810SAnil Ravindranath * 26989a36810SAnil Ravindranath * @scsi_dev: scsi device struct 27089a36810SAnil Ravindranath * 27189a36810SAnil Ravindranath * This is called by mid-layer before removing a device. Pointer assignments 27289a36810SAnil Ravindranath * done in pmcraid_slave_alloc will be reset to NULL here. 27389a36810SAnil Ravindranath * 27489a36810SAnil Ravindranath * Return value 27589a36810SAnil Ravindranath * none 27689a36810SAnil Ravindranath */ 27789a36810SAnil Ravindranath static void pmcraid_slave_destroy(struct scsi_device *scsi_dev) 27889a36810SAnil Ravindranath { 27989a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 28089a36810SAnil Ravindranath 28189a36810SAnil Ravindranath res = (struct pmcraid_resource_entry *)scsi_dev->hostdata; 28289a36810SAnil Ravindranath 28389a36810SAnil Ravindranath if (res) 28489a36810SAnil Ravindranath res->scsi_dev = NULL; 28589a36810SAnil Ravindranath 28689a36810SAnil Ravindranath scsi_dev->hostdata = NULL; 28789a36810SAnil Ravindranath } 28889a36810SAnil Ravindranath 28989a36810SAnil Ravindranath /** 29089a36810SAnil Ravindranath * pmcraid_change_queue_depth - Change the device's queue depth 29189a36810SAnil Ravindranath * @scsi_dev: scsi device struct 29289a36810SAnil Ravindranath * @depth: depth to set 293e881a172SMike Christie * @reason: calling context 29489a36810SAnil Ravindranath * 29589a36810SAnil Ravindranath * Return value 29689a36810SAnil Ravindranath * actual depth set 29789a36810SAnil Ravindranath */ 298e881a172SMike Christie static int pmcraid_change_queue_depth(struct scsi_device *scsi_dev, int depth, 299e881a172SMike Christie int reason) 30089a36810SAnil Ravindranath { 301e881a172SMike Christie if (reason != SCSI_QDEPTH_DEFAULT) 302e881a172SMike Christie return -EOPNOTSUPP; 303e881a172SMike Christie 30489a36810SAnil Ravindranath if (depth > PMCRAID_MAX_CMD_PER_LUN) 30589a36810SAnil Ravindranath depth = PMCRAID_MAX_CMD_PER_LUN; 30689a36810SAnil Ravindranath 30789a36810SAnil Ravindranath scsi_adjust_queue_depth(scsi_dev, scsi_get_tag_type(scsi_dev), depth); 30889a36810SAnil Ravindranath 30989a36810SAnil Ravindranath return scsi_dev->queue_depth; 31089a36810SAnil Ravindranath } 31189a36810SAnil Ravindranath 31289a36810SAnil Ravindranath /** 31389a36810SAnil Ravindranath * pmcraid_change_queue_type - Change the device's queue type 31489a36810SAnil Ravindranath * @scsi_dev: scsi device struct 31589a36810SAnil Ravindranath * @tag: type of tags to use 31689a36810SAnil Ravindranath * 31789a36810SAnil Ravindranath * Return value: 31889a36810SAnil Ravindranath * actual queue type set 31989a36810SAnil Ravindranath */ 32089a36810SAnil Ravindranath static int pmcraid_change_queue_type(struct scsi_device *scsi_dev, int tag) 32189a36810SAnil Ravindranath { 32289a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 32389a36810SAnil Ravindranath 32489a36810SAnil Ravindranath res = (struct pmcraid_resource_entry *)scsi_dev->hostdata; 32589a36810SAnil Ravindranath 32689a36810SAnil Ravindranath if ((res) && scsi_dev->tagged_supported && 32789a36810SAnil Ravindranath (RES_IS_GSCSI(res->cfg_entry) || RES_IS_VSET(res->cfg_entry))) { 32889a36810SAnil Ravindranath scsi_set_tag_type(scsi_dev, tag); 32989a36810SAnil Ravindranath 33089a36810SAnil Ravindranath if (tag) 33189a36810SAnil Ravindranath scsi_activate_tcq(scsi_dev, scsi_dev->queue_depth); 33289a36810SAnil Ravindranath else 33389a36810SAnil Ravindranath scsi_deactivate_tcq(scsi_dev, scsi_dev->queue_depth); 33489a36810SAnil Ravindranath } else 33589a36810SAnil Ravindranath tag = 0; 33689a36810SAnil Ravindranath 33789a36810SAnil Ravindranath return tag; 33889a36810SAnil Ravindranath } 33989a36810SAnil Ravindranath 34089a36810SAnil Ravindranath 34189a36810SAnil Ravindranath /** 34289a36810SAnil Ravindranath * pmcraid_init_cmdblk - initializes a command block 34389a36810SAnil Ravindranath * 34489a36810SAnil Ravindranath * @cmd: pointer to struct pmcraid_cmd to be initialized 34589a36810SAnil Ravindranath * @index: if >=0 first time initialization; otherwise reinitialization 34689a36810SAnil Ravindranath * 34789a36810SAnil Ravindranath * Return Value 34889a36810SAnil Ravindranath * None 34989a36810SAnil Ravindranath */ 35089a36810SAnil Ravindranath void pmcraid_init_cmdblk(struct pmcraid_cmd *cmd, int index) 35189a36810SAnil Ravindranath { 35289a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &(cmd->ioa_cb->ioarcb); 35389a36810SAnil Ravindranath dma_addr_t dma_addr = cmd->ioa_cb_bus_addr; 35489a36810SAnil Ravindranath 35589a36810SAnil Ravindranath if (index >= 0) { 35689a36810SAnil Ravindranath /* first time initialization (called from probe) */ 35789a36810SAnil Ravindranath u32 ioasa_offset = 35889a36810SAnil Ravindranath offsetof(struct pmcraid_control_block, ioasa); 35989a36810SAnil Ravindranath 36089a36810SAnil Ravindranath cmd->index = index; 36189a36810SAnil Ravindranath ioarcb->response_handle = cpu_to_le32(index << 2); 36289a36810SAnil Ravindranath ioarcb->ioarcb_bus_addr = cpu_to_le64(dma_addr); 36389a36810SAnil Ravindranath ioarcb->ioasa_bus_addr = cpu_to_le64(dma_addr + ioasa_offset); 36489a36810SAnil Ravindranath ioarcb->ioasa_len = cpu_to_le16(sizeof(struct pmcraid_ioasa)); 36589a36810SAnil Ravindranath } else { 36689a36810SAnil Ravindranath /* re-initialization of various lengths, called once command is 36789a36810SAnil Ravindranath * processed by IOA 36889a36810SAnil Ravindranath */ 36989a36810SAnil Ravindranath memset(&cmd->ioa_cb->ioarcb.cdb, 0, PMCRAID_MAX_CDB_LEN); 370c20c4267SAnil Ravindranath ioarcb->hrrq_id = 0; 37189a36810SAnil Ravindranath ioarcb->request_flags0 = 0; 37289a36810SAnil Ravindranath ioarcb->request_flags1 = 0; 37389a36810SAnil Ravindranath ioarcb->cmd_timeout = 0; 37489a36810SAnil Ravindranath ioarcb->ioarcb_bus_addr &= (~0x1FULL); 37589a36810SAnil Ravindranath ioarcb->ioadl_bus_addr = 0; 37689a36810SAnil Ravindranath ioarcb->ioadl_length = 0; 37789a36810SAnil Ravindranath ioarcb->data_transfer_length = 0; 37889a36810SAnil Ravindranath ioarcb->add_cmd_param_length = 0; 37989a36810SAnil Ravindranath ioarcb->add_cmd_param_offset = 0; 38089a36810SAnil Ravindranath cmd->ioa_cb->ioasa.ioasc = 0; 38189a36810SAnil Ravindranath cmd->ioa_cb->ioasa.residual_data_length = 0; 382c20c4267SAnil Ravindranath cmd->time_left = 0; 38389a36810SAnil Ravindranath } 38489a36810SAnil Ravindranath 38589a36810SAnil Ravindranath cmd->cmd_done = NULL; 38689a36810SAnil Ravindranath cmd->scsi_cmd = NULL; 38789a36810SAnil Ravindranath cmd->release = 0; 38889a36810SAnil Ravindranath cmd->completion_req = 0; 389c20c4267SAnil Ravindranath cmd->sense_buffer = 0; 390c20c4267SAnil Ravindranath cmd->sense_buffer_dma = 0; 39189a36810SAnil Ravindranath cmd->dma_handle = 0; 39289a36810SAnil Ravindranath init_timer(&cmd->timer); 39389a36810SAnil Ravindranath } 39489a36810SAnil Ravindranath 39589a36810SAnil Ravindranath /** 39689a36810SAnil Ravindranath * pmcraid_reinit_cmdblk - reinitialize a command block 39789a36810SAnil Ravindranath * 39889a36810SAnil Ravindranath * @cmd: pointer to struct pmcraid_cmd to be reinitialized 39989a36810SAnil Ravindranath * 40089a36810SAnil Ravindranath * Return Value 40189a36810SAnil Ravindranath * None 40289a36810SAnil Ravindranath */ 40389a36810SAnil Ravindranath static void pmcraid_reinit_cmdblk(struct pmcraid_cmd *cmd) 40489a36810SAnil Ravindranath { 40589a36810SAnil Ravindranath pmcraid_init_cmdblk(cmd, -1); 40689a36810SAnil Ravindranath } 40789a36810SAnil Ravindranath 40889a36810SAnil Ravindranath /** 40989a36810SAnil Ravindranath * pmcraid_get_free_cmd - get a free cmd block from command block pool 41089a36810SAnil Ravindranath * @pinstance: adapter instance structure 41189a36810SAnil Ravindranath * 41289a36810SAnil Ravindranath * Return Value: 41389a36810SAnil Ravindranath * returns pointer to cmd block or NULL if no blocks are available 41489a36810SAnil Ravindranath */ 41589a36810SAnil Ravindranath static struct pmcraid_cmd *pmcraid_get_free_cmd( 41689a36810SAnil Ravindranath struct pmcraid_instance *pinstance 41789a36810SAnil Ravindranath ) 41889a36810SAnil Ravindranath { 41989a36810SAnil Ravindranath struct pmcraid_cmd *cmd = NULL; 42089a36810SAnil Ravindranath unsigned long lock_flags; 42189a36810SAnil Ravindranath 42289a36810SAnil Ravindranath /* free cmd block list is protected by free_pool_lock */ 42389a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->free_pool_lock, lock_flags); 42489a36810SAnil Ravindranath 42589a36810SAnil Ravindranath if (!list_empty(&pinstance->free_cmd_pool)) { 42689a36810SAnil Ravindranath cmd = list_entry(pinstance->free_cmd_pool.next, 42789a36810SAnil Ravindranath struct pmcraid_cmd, free_list); 42889a36810SAnil Ravindranath list_del(&cmd->free_list); 42989a36810SAnil Ravindranath } 43089a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->free_pool_lock, lock_flags); 43189a36810SAnil Ravindranath 43289a36810SAnil Ravindranath /* Initialize the command block before giving it the caller */ 43389a36810SAnil Ravindranath if (cmd != NULL) 43489a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 43589a36810SAnil Ravindranath return cmd; 43689a36810SAnil Ravindranath } 43789a36810SAnil Ravindranath 43889a36810SAnil Ravindranath /** 43989a36810SAnil Ravindranath * pmcraid_return_cmd - return a completed command block back into free pool 44089a36810SAnil Ravindranath * @cmd: pointer to the command block 44189a36810SAnil Ravindranath * 44289a36810SAnil Ravindranath * Return Value: 44389a36810SAnil Ravindranath * nothing 44489a36810SAnil Ravindranath */ 44589a36810SAnil Ravindranath void pmcraid_return_cmd(struct pmcraid_cmd *cmd) 44689a36810SAnil Ravindranath { 44789a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 44889a36810SAnil Ravindranath unsigned long lock_flags; 44989a36810SAnil Ravindranath 45089a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->free_pool_lock, lock_flags); 45189a36810SAnil Ravindranath list_add_tail(&cmd->free_list, &pinstance->free_cmd_pool); 45289a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->free_pool_lock, lock_flags); 45389a36810SAnil Ravindranath } 45489a36810SAnil Ravindranath 45589a36810SAnil Ravindranath /** 45689a36810SAnil Ravindranath * pmcraid_read_interrupts - reads IOA interrupts 45789a36810SAnil Ravindranath * 45889a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 45989a36810SAnil Ravindranath * 46089a36810SAnil Ravindranath * Return value 46189a36810SAnil Ravindranath * interrupts read from IOA 46289a36810SAnil Ravindranath */ 46389a36810SAnil Ravindranath static u32 pmcraid_read_interrupts(struct pmcraid_instance *pinstance) 46489a36810SAnil Ravindranath { 465c20c4267SAnil Ravindranath return (pinstance->interrupt_mode) ? 466c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.ioa_host_msix_interrupt_reg) : 467c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.ioa_host_interrupt_reg); 46889a36810SAnil Ravindranath } 46989a36810SAnil Ravindranath 47089a36810SAnil Ravindranath /** 47189a36810SAnil Ravindranath * pmcraid_disable_interrupts - Masks and clears all specified interrupts 47289a36810SAnil Ravindranath * 47389a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 47489a36810SAnil Ravindranath * @intrs: interrupts to disable 47589a36810SAnil Ravindranath * 47689a36810SAnil Ravindranath * Return Value 47789a36810SAnil Ravindranath * None 47889a36810SAnil Ravindranath */ 47989a36810SAnil Ravindranath static void pmcraid_disable_interrupts( 48089a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 48189a36810SAnil Ravindranath u32 intrs 48289a36810SAnil Ravindranath ) 48389a36810SAnil Ravindranath { 48489a36810SAnil Ravindranath u32 gmask = ioread32(pinstance->int_regs.global_interrupt_mask_reg); 48589a36810SAnil Ravindranath u32 nmask = gmask | GLOBAL_INTERRUPT_MASK; 48689a36810SAnil Ravindranath 48789a36810SAnil Ravindranath iowrite32(intrs, pinstance->int_regs.ioa_host_interrupt_clr_reg); 488c20c4267SAnil Ravindranath iowrite32(nmask, pinstance->int_regs.global_interrupt_mask_reg); 489c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.global_interrupt_mask_reg); 490c20c4267SAnil Ravindranath 491c20c4267SAnil Ravindranath if (!pinstance->interrupt_mode) { 492c20c4267SAnil Ravindranath iowrite32(intrs, 493c20c4267SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_mask_reg); 49489a36810SAnil Ravindranath ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg); 49589a36810SAnil Ravindranath } 496c20c4267SAnil Ravindranath } 49789a36810SAnil Ravindranath 49889a36810SAnil Ravindranath /** 49989a36810SAnil Ravindranath * pmcraid_enable_interrupts - Enables specified interrupts 50089a36810SAnil Ravindranath * 50189a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 50289a36810SAnil Ravindranath * @intr: interrupts to enable 50389a36810SAnil Ravindranath * 50489a36810SAnil Ravindranath * Return Value 50589a36810SAnil Ravindranath * None 50689a36810SAnil Ravindranath */ 50789a36810SAnil Ravindranath static void pmcraid_enable_interrupts( 50889a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 50989a36810SAnil Ravindranath u32 intrs 51089a36810SAnil Ravindranath ) 51189a36810SAnil Ravindranath { 51289a36810SAnil Ravindranath u32 gmask = ioread32(pinstance->int_regs.global_interrupt_mask_reg); 51389a36810SAnil Ravindranath u32 nmask = gmask & (~GLOBAL_INTERRUPT_MASK); 51489a36810SAnil Ravindranath 51589a36810SAnil Ravindranath iowrite32(nmask, pinstance->int_regs.global_interrupt_mask_reg); 516c20c4267SAnil Ravindranath 517c20c4267SAnil Ravindranath if (!pinstance->interrupt_mode) { 518c20c4267SAnil Ravindranath iowrite32(~intrs, 519c20c4267SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_mask_reg); 52089a36810SAnil Ravindranath ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg); 521c20c4267SAnil Ravindranath } 52289a36810SAnil Ravindranath 52389a36810SAnil Ravindranath pmcraid_info("enabled interrupts global mask = %x intr_mask = %x\n", 52489a36810SAnil Ravindranath ioread32(pinstance->int_regs.global_interrupt_mask_reg), 52589a36810SAnil Ravindranath ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg)); 52689a36810SAnil Ravindranath } 52789a36810SAnil Ravindranath 52889a36810SAnil Ravindranath /** 529c20c4267SAnil Ravindranath * pmcraid_clr_trans_op - clear trans to op interrupt 530c20c4267SAnil Ravindranath * 531c20c4267SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 532c20c4267SAnil Ravindranath * 533c20c4267SAnil Ravindranath * Return Value 534c20c4267SAnil Ravindranath * None 535c20c4267SAnil Ravindranath */ 536c20c4267SAnil Ravindranath static void pmcraid_clr_trans_op( 537c20c4267SAnil Ravindranath struct pmcraid_instance *pinstance 538c20c4267SAnil Ravindranath ) 539c20c4267SAnil Ravindranath { 540c20c4267SAnil Ravindranath unsigned long lock_flags; 541c20c4267SAnil Ravindranath 542c20c4267SAnil Ravindranath if (!pinstance->interrupt_mode) { 543c20c4267SAnil Ravindranath iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, 544c20c4267SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_mask_reg); 545c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg); 546c20c4267SAnil Ravindranath iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, 547c20c4267SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_clr_reg); 548c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.ioa_host_interrupt_clr_reg); 549c20c4267SAnil Ravindranath } 550c20c4267SAnil Ravindranath 551c20c4267SAnil Ravindranath if (pinstance->reset_cmd != NULL) { 552c20c4267SAnil Ravindranath del_timer(&pinstance->reset_cmd->timer); 553c20c4267SAnil Ravindranath spin_lock_irqsave( 554c20c4267SAnil Ravindranath pinstance->host->host_lock, lock_flags); 555c20c4267SAnil Ravindranath pinstance->reset_cmd->cmd_done(pinstance->reset_cmd); 556c20c4267SAnil Ravindranath spin_unlock_irqrestore( 557c20c4267SAnil Ravindranath pinstance->host->host_lock, lock_flags); 558c20c4267SAnil Ravindranath } 559c20c4267SAnil Ravindranath } 560c20c4267SAnil Ravindranath 561c20c4267SAnil Ravindranath /** 56289a36810SAnil Ravindranath * pmcraid_reset_type - Determine the required reset type 56389a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 56489a36810SAnil Ravindranath * 56589a36810SAnil Ravindranath * IOA requires hard reset if any of the following conditions is true. 56689a36810SAnil Ravindranath * 1. If HRRQ valid interrupt is not masked 56789a36810SAnil Ravindranath * 2. IOA reset alert doorbell is set 56889a36810SAnil Ravindranath * 3. If there are any error interrupts 56989a36810SAnil Ravindranath */ 57089a36810SAnil Ravindranath static void pmcraid_reset_type(struct pmcraid_instance *pinstance) 57189a36810SAnil Ravindranath { 57289a36810SAnil Ravindranath u32 mask; 57389a36810SAnil Ravindranath u32 intrs; 57489a36810SAnil Ravindranath u32 alerts; 57589a36810SAnil Ravindranath 57689a36810SAnil Ravindranath mask = ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg); 57789a36810SAnil Ravindranath intrs = ioread32(pinstance->int_regs.ioa_host_interrupt_reg); 57889a36810SAnil Ravindranath alerts = ioread32(pinstance->int_regs.host_ioa_interrupt_reg); 57989a36810SAnil Ravindranath 58089a36810SAnil Ravindranath if ((mask & INTRS_HRRQ_VALID) == 0 || 58189a36810SAnil Ravindranath (alerts & DOORBELL_IOA_RESET_ALERT) || 58289a36810SAnil Ravindranath (intrs & PMCRAID_ERROR_INTERRUPTS)) { 58389a36810SAnil Ravindranath pmcraid_info("IOA requires hard reset\n"); 58489a36810SAnil Ravindranath pinstance->ioa_hard_reset = 1; 58589a36810SAnil Ravindranath } 58689a36810SAnil Ravindranath 58789a36810SAnil Ravindranath /* If unit check is active, trigger the dump */ 58889a36810SAnil Ravindranath if (intrs & INTRS_IOA_UNIT_CHECK) 58989a36810SAnil Ravindranath pinstance->ioa_unit_check = 1; 59089a36810SAnil Ravindranath } 59189a36810SAnil Ravindranath 59289a36810SAnil Ravindranath /** 59389a36810SAnil Ravindranath * pmcraid_bist_done - completion function for PCI BIST 59489a36810SAnil Ravindranath * @cmd: pointer to reset command 59589a36810SAnil Ravindranath * Return Value 59689a36810SAnil Ravindranath * none 59789a36810SAnil Ravindranath */ 59889a36810SAnil Ravindranath 59989a36810SAnil Ravindranath static void pmcraid_ioa_reset(struct pmcraid_cmd *); 60089a36810SAnil Ravindranath 60189a36810SAnil Ravindranath static void pmcraid_bist_done(struct pmcraid_cmd *cmd) 60289a36810SAnil Ravindranath { 60389a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 60489a36810SAnil Ravindranath unsigned long lock_flags; 60589a36810SAnil Ravindranath int rc; 60689a36810SAnil Ravindranath u16 pci_reg; 60789a36810SAnil Ravindranath 60889a36810SAnil Ravindranath rc = pci_read_config_word(pinstance->pdev, PCI_COMMAND, &pci_reg); 60989a36810SAnil Ravindranath 61089a36810SAnil Ravindranath /* If PCI config space can't be accessed wait for another two secs */ 61189a36810SAnil Ravindranath if ((rc != PCIBIOS_SUCCESSFUL || (!(pci_reg & PCI_COMMAND_MEMORY))) && 612c20c4267SAnil Ravindranath cmd->time_left > 0) { 61389a36810SAnil Ravindranath pmcraid_info("BIST not complete, waiting another 2 secs\n"); 614c20c4267SAnil Ravindranath cmd->timer.expires = jiffies + cmd->time_left; 615c20c4267SAnil Ravindranath cmd->time_left = 0; 61689a36810SAnil Ravindranath cmd->timer.data = (unsigned long)cmd; 61789a36810SAnil Ravindranath cmd->timer.function = 61889a36810SAnil Ravindranath (void (*)(unsigned long))pmcraid_bist_done; 61989a36810SAnil Ravindranath add_timer(&cmd->timer); 62089a36810SAnil Ravindranath } else { 621c20c4267SAnil Ravindranath cmd->time_left = 0; 62289a36810SAnil Ravindranath pmcraid_info("BIST is complete, proceeding with reset\n"); 62389a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 62489a36810SAnil Ravindranath pmcraid_ioa_reset(cmd); 62589a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 62689a36810SAnil Ravindranath } 62789a36810SAnil Ravindranath } 62889a36810SAnil Ravindranath 62989a36810SAnil Ravindranath /** 63089a36810SAnil Ravindranath * pmcraid_start_bist - starts BIST 63189a36810SAnil Ravindranath * @cmd: pointer to reset cmd 63289a36810SAnil Ravindranath * Return Value 63389a36810SAnil Ravindranath * none 63489a36810SAnil Ravindranath */ 63589a36810SAnil Ravindranath static void pmcraid_start_bist(struct pmcraid_cmd *cmd) 63689a36810SAnil Ravindranath { 63789a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 63889a36810SAnil Ravindranath u32 doorbells, intrs; 63989a36810SAnil Ravindranath 64089a36810SAnil Ravindranath /* proceed with bist and wait for 2 seconds */ 64189a36810SAnil Ravindranath iowrite32(DOORBELL_IOA_START_BIST, 64289a36810SAnil Ravindranath pinstance->int_regs.host_ioa_interrupt_reg); 64389a36810SAnil Ravindranath doorbells = ioread32(pinstance->int_regs.host_ioa_interrupt_reg); 64489a36810SAnil Ravindranath intrs = ioread32(pinstance->int_regs.ioa_host_interrupt_reg); 64589a36810SAnil Ravindranath pmcraid_info("doorbells after start bist: %x intrs: %x\n", 64689a36810SAnil Ravindranath doorbells, intrs); 64789a36810SAnil Ravindranath 648c20c4267SAnil Ravindranath cmd->time_left = msecs_to_jiffies(PMCRAID_BIST_TIMEOUT); 64989a36810SAnil Ravindranath cmd->timer.data = (unsigned long)cmd; 65089a36810SAnil Ravindranath cmd->timer.expires = jiffies + msecs_to_jiffies(PMCRAID_BIST_TIMEOUT); 65189a36810SAnil Ravindranath cmd->timer.function = (void (*)(unsigned long))pmcraid_bist_done; 65289a36810SAnil Ravindranath add_timer(&cmd->timer); 65389a36810SAnil Ravindranath } 65489a36810SAnil Ravindranath 65589a36810SAnil Ravindranath /** 65689a36810SAnil Ravindranath * pmcraid_reset_alert_done - completion routine for reset_alert 65789a36810SAnil Ravindranath * @cmd: pointer to command block used in reset sequence 65889a36810SAnil Ravindranath * Return value 65989a36810SAnil Ravindranath * None 66089a36810SAnil Ravindranath */ 66189a36810SAnil Ravindranath static void pmcraid_reset_alert_done(struct pmcraid_cmd *cmd) 66289a36810SAnil Ravindranath { 66389a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 66489a36810SAnil Ravindranath u32 status = ioread32(pinstance->ioa_status); 66589a36810SAnil Ravindranath unsigned long lock_flags; 66689a36810SAnil Ravindranath 66789a36810SAnil Ravindranath /* if the critical operation in progress bit is set or the wait times 66889a36810SAnil Ravindranath * out, invoke reset engine to proceed with hard reset. If there is 66989a36810SAnil Ravindranath * some more time to wait, restart the timer 67089a36810SAnil Ravindranath */ 67189a36810SAnil Ravindranath if (((status & INTRS_CRITICAL_OP_IN_PROGRESS) == 0) || 672c20c4267SAnil Ravindranath cmd->time_left <= 0) { 67389a36810SAnil Ravindranath pmcraid_info("critical op is reset proceeding with reset\n"); 67489a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 67589a36810SAnil Ravindranath pmcraid_ioa_reset(cmd); 67689a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 67789a36810SAnil Ravindranath } else { 67889a36810SAnil Ravindranath pmcraid_info("critical op is not yet reset waiting again\n"); 67989a36810SAnil Ravindranath /* restart timer if some more time is available to wait */ 680c20c4267SAnil Ravindranath cmd->time_left -= PMCRAID_CHECK_FOR_RESET_TIMEOUT; 68189a36810SAnil Ravindranath cmd->timer.data = (unsigned long)cmd; 68289a36810SAnil Ravindranath cmd->timer.expires = jiffies + PMCRAID_CHECK_FOR_RESET_TIMEOUT; 68389a36810SAnil Ravindranath cmd->timer.function = 68489a36810SAnil Ravindranath (void (*)(unsigned long))pmcraid_reset_alert_done; 68589a36810SAnil Ravindranath add_timer(&cmd->timer); 68689a36810SAnil Ravindranath } 68789a36810SAnil Ravindranath } 68889a36810SAnil Ravindranath 68989a36810SAnil Ravindranath /** 69089a36810SAnil Ravindranath * pmcraid_reset_alert - alerts IOA for a possible reset 69189a36810SAnil Ravindranath * @cmd : command block to be used for reset sequence. 69289a36810SAnil Ravindranath * 69389a36810SAnil Ravindranath * Return Value 69489a36810SAnil Ravindranath * returns 0 if pci config-space is accessible and RESET_DOORBELL is 69589a36810SAnil Ravindranath * successfully written to IOA. Returns non-zero in case pci_config_space 69689a36810SAnil Ravindranath * is not accessible 69789a36810SAnil Ravindranath */ 698c20c4267SAnil Ravindranath static void pmcraid_notify_ioastate(struct pmcraid_instance *, u32); 69989a36810SAnil Ravindranath static void pmcraid_reset_alert(struct pmcraid_cmd *cmd) 70089a36810SAnil Ravindranath { 70189a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 70289a36810SAnil Ravindranath u32 doorbells; 70389a36810SAnil Ravindranath int rc; 70489a36810SAnil Ravindranath u16 pci_reg; 70589a36810SAnil Ravindranath 70689a36810SAnil Ravindranath /* If we are able to access IOA PCI config space, alert IOA that we are 70789a36810SAnil Ravindranath * going to reset it soon. This enables IOA to preserv persistent error 70889a36810SAnil Ravindranath * data if any. In case memory space is not accessible, proceed with 70989a36810SAnil Ravindranath * BIST or slot_reset 71089a36810SAnil Ravindranath */ 71189a36810SAnil Ravindranath rc = pci_read_config_word(pinstance->pdev, PCI_COMMAND, &pci_reg); 71289a36810SAnil Ravindranath if ((rc == PCIBIOS_SUCCESSFUL) && (pci_reg & PCI_COMMAND_MEMORY)) { 71389a36810SAnil Ravindranath 71489a36810SAnil Ravindranath /* wait for IOA permission i.e until CRITICAL_OPERATION bit is 71589a36810SAnil Ravindranath * reset IOA doesn't generate any interrupts when CRITICAL 71689a36810SAnil Ravindranath * OPERATION bit is reset. A timer is started to wait for this 71789a36810SAnil Ravindranath * bit to be reset. 71889a36810SAnil Ravindranath */ 719c20c4267SAnil Ravindranath cmd->time_left = PMCRAID_RESET_TIMEOUT; 72089a36810SAnil Ravindranath cmd->timer.data = (unsigned long)cmd; 72189a36810SAnil Ravindranath cmd->timer.expires = jiffies + PMCRAID_CHECK_FOR_RESET_TIMEOUT; 72289a36810SAnil Ravindranath cmd->timer.function = 72389a36810SAnil Ravindranath (void (*)(unsigned long))pmcraid_reset_alert_done; 72489a36810SAnil Ravindranath add_timer(&cmd->timer); 72589a36810SAnil Ravindranath 72689a36810SAnil Ravindranath iowrite32(DOORBELL_IOA_RESET_ALERT, 72789a36810SAnil Ravindranath pinstance->int_regs.host_ioa_interrupt_reg); 72889a36810SAnil Ravindranath doorbells = 72989a36810SAnil Ravindranath ioread32(pinstance->int_regs.host_ioa_interrupt_reg); 73089a36810SAnil Ravindranath pmcraid_info("doorbells after reset alert: %x\n", doorbells); 73189a36810SAnil Ravindranath } else { 73289a36810SAnil Ravindranath pmcraid_info("PCI config is not accessible starting BIST\n"); 73389a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_HARD_RESET; 73489a36810SAnil Ravindranath pmcraid_start_bist(cmd); 73589a36810SAnil Ravindranath } 73689a36810SAnil Ravindranath } 73789a36810SAnil Ravindranath 73889a36810SAnil Ravindranath /** 73989a36810SAnil Ravindranath * pmcraid_timeout_handler - Timeout handler for internally generated ops 74089a36810SAnil Ravindranath * 74189a36810SAnil Ravindranath * @cmd : pointer to command structure, that got timedout 74289a36810SAnil Ravindranath * 74389a36810SAnil Ravindranath * This function blocks host requests and initiates an adapter reset. 74489a36810SAnil Ravindranath * 74589a36810SAnil Ravindranath * Return value: 74689a36810SAnil Ravindranath * None 74789a36810SAnil Ravindranath */ 74889a36810SAnil Ravindranath static void pmcraid_timeout_handler(struct pmcraid_cmd *cmd) 74989a36810SAnil Ravindranath { 75089a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 75189a36810SAnil Ravindranath unsigned long lock_flags; 75289a36810SAnil Ravindranath 75334876402SAnil Ravindranath dev_info(&pinstance->pdev->dev, 754c20c4267SAnil Ravindranath "Adapter being reset due to cmd(CDB[0] = %x) timeout\n", 755c20c4267SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0]); 75689a36810SAnil Ravindranath 75789a36810SAnil Ravindranath /* Command timeouts result in hard reset sequence. The command that got 75889a36810SAnil Ravindranath * timed out may be the one used as part of reset sequence. In this 75989a36810SAnil Ravindranath * case restart reset sequence using the same command block even if 76089a36810SAnil Ravindranath * reset is in progress. Otherwise fail this command and get a free 76189a36810SAnil Ravindranath * command block to restart the reset sequence. 76289a36810SAnil Ravindranath */ 76389a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 76489a36810SAnil Ravindranath if (!pinstance->ioa_reset_in_progress) { 76589a36810SAnil Ravindranath pinstance->ioa_reset_attempts = 0; 76689a36810SAnil Ravindranath cmd = pmcraid_get_free_cmd(pinstance); 76789a36810SAnil Ravindranath 76889a36810SAnil Ravindranath /* If we are out of command blocks, just return here itself. 76989a36810SAnil Ravindranath * Some other command's timeout handler can do the reset job 77089a36810SAnil Ravindranath */ 77189a36810SAnil Ravindranath if (cmd == NULL) { 77289a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 77389a36810SAnil Ravindranath lock_flags); 77489a36810SAnil Ravindranath pmcraid_err("no free cmnd block for timeout handler\n"); 77589a36810SAnil Ravindranath return; 77689a36810SAnil Ravindranath } 77789a36810SAnil Ravindranath 77889a36810SAnil Ravindranath pinstance->reset_cmd = cmd; 77989a36810SAnil Ravindranath pinstance->ioa_reset_in_progress = 1; 78089a36810SAnil Ravindranath } else { 78189a36810SAnil Ravindranath pmcraid_info("reset is already in progress\n"); 78289a36810SAnil Ravindranath 78389a36810SAnil Ravindranath if (pinstance->reset_cmd != cmd) { 78489a36810SAnil Ravindranath /* This command should have been given to IOA, this 78589a36810SAnil Ravindranath * command will be completed by fail_outstanding_cmds 78689a36810SAnil Ravindranath * anyway 78789a36810SAnil Ravindranath */ 78889a36810SAnil Ravindranath pmcraid_err("cmd is pending but reset in progress\n"); 78989a36810SAnil Ravindranath } 79089a36810SAnil Ravindranath 79189a36810SAnil Ravindranath /* If this command was being used as part of the reset 79289a36810SAnil Ravindranath * sequence, set cmd_done pointer to pmcraid_ioa_reset. This 79389a36810SAnil Ravindranath * causes fail_outstanding_commands not to return the command 79489a36810SAnil Ravindranath * block back to free pool 79589a36810SAnil Ravindranath */ 79689a36810SAnil Ravindranath if (cmd == pinstance->reset_cmd) 79789a36810SAnil Ravindranath cmd->cmd_done = pmcraid_ioa_reset; 79889a36810SAnil Ravindranath } 79989a36810SAnil Ravindranath 800c20c4267SAnil Ravindranath /* Notify apps of important IOA bringup/bringdown sequences */ 801c20c4267SAnil Ravindranath if (pinstance->scn.ioa_state != PMC_DEVICE_EVENT_RESET_START && 802c20c4267SAnil Ravindranath pinstance->scn.ioa_state != PMC_DEVICE_EVENT_SHUTDOWN_START) 803c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, 804c20c4267SAnil Ravindranath PMC_DEVICE_EVENT_RESET_START); 805c20c4267SAnil Ravindranath 80689a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; 80789a36810SAnil Ravindranath scsi_block_requests(pinstance->host); 80889a36810SAnil Ravindranath pmcraid_reset_alert(cmd); 80989a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 81089a36810SAnil Ravindranath } 81189a36810SAnil Ravindranath 81289a36810SAnil Ravindranath /** 81389a36810SAnil Ravindranath * pmcraid_internal_done - completion routine for internally generated cmds 81489a36810SAnil Ravindranath * 81589a36810SAnil Ravindranath * @cmd: command that got response from IOA 81689a36810SAnil Ravindranath * 81789a36810SAnil Ravindranath * Return Value: 81889a36810SAnil Ravindranath * none 81989a36810SAnil Ravindranath */ 82089a36810SAnil Ravindranath static void pmcraid_internal_done(struct pmcraid_cmd *cmd) 82189a36810SAnil Ravindranath { 82289a36810SAnil Ravindranath pmcraid_info("response internal cmd CDB[0] = %x ioasc = %x\n", 82389a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 82489a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)); 82589a36810SAnil Ravindranath 82689a36810SAnil Ravindranath /* Some of the internal commands are sent with callers blocking for the 82789a36810SAnil Ravindranath * response. Same will be indicated as part of cmd->completion_req 82889a36810SAnil Ravindranath * field. Response path needs to wake up any waiters waiting for cmd 82989a36810SAnil Ravindranath * completion if this flag is set. 83089a36810SAnil Ravindranath */ 83189a36810SAnil Ravindranath if (cmd->completion_req) { 83289a36810SAnil Ravindranath cmd->completion_req = 0; 83389a36810SAnil Ravindranath complete(&cmd->wait_for_completion); 83489a36810SAnil Ravindranath } 83589a36810SAnil Ravindranath 83689a36810SAnil Ravindranath /* most of the internal commands are completed by caller itself, so 83789a36810SAnil Ravindranath * no need to return the command block back to free pool until we are 83889a36810SAnil Ravindranath * required to do so (e.g once done with initialization). 83989a36810SAnil Ravindranath */ 84089a36810SAnil Ravindranath if (cmd->release) { 84189a36810SAnil Ravindranath cmd->release = 0; 84289a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 84389a36810SAnil Ravindranath } 84489a36810SAnil Ravindranath } 84589a36810SAnil Ravindranath 84689a36810SAnil Ravindranath /** 84789a36810SAnil Ravindranath * pmcraid_reinit_cfgtable_done - done function for cfg table reinitialization 84889a36810SAnil Ravindranath * 84989a36810SAnil Ravindranath * @cmd: command that got response from IOA 85089a36810SAnil Ravindranath * 85189a36810SAnil Ravindranath * This routine is called after driver re-reads configuration table due to a 85289a36810SAnil Ravindranath * lost CCN. It returns the command block back to free pool and schedules 85389a36810SAnil Ravindranath * worker thread to add/delete devices into the system. 85489a36810SAnil Ravindranath * 85589a36810SAnil Ravindranath * Return Value: 85689a36810SAnil Ravindranath * none 85789a36810SAnil Ravindranath */ 85889a36810SAnil Ravindranath static void pmcraid_reinit_cfgtable_done(struct pmcraid_cmd *cmd) 85989a36810SAnil Ravindranath { 86089a36810SAnil Ravindranath pmcraid_info("response internal cmd CDB[0] = %x ioasc = %x\n", 86189a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 86289a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)); 86389a36810SAnil Ravindranath 86489a36810SAnil Ravindranath if (cmd->release) { 86589a36810SAnil Ravindranath cmd->release = 0; 86689a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 86789a36810SAnil Ravindranath } 86889a36810SAnil Ravindranath pmcraid_info("scheduling worker for config table reinitialization\n"); 86989a36810SAnil Ravindranath schedule_work(&cmd->drv_inst->worker_q); 87089a36810SAnil Ravindranath } 87189a36810SAnil Ravindranath 87289a36810SAnil Ravindranath /** 87389a36810SAnil Ravindranath * pmcraid_erp_done - Process completion of SCSI error response from device 87489a36810SAnil Ravindranath * @cmd: pmcraid_command 87589a36810SAnil Ravindranath * 87689a36810SAnil Ravindranath * This function copies the sense buffer into the scsi_cmd struct and completes 87789a36810SAnil Ravindranath * scsi_cmd by calling scsi_done function. 87889a36810SAnil Ravindranath * 87989a36810SAnil Ravindranath * Return value: 88089a36810SAnil Ravindranath * none 88189a36810SAnil Ravindranath */ 88289a36810SAnil Ravindranath static void pmcraid_erp_done(struct pmcraid_cmd *cmd) 88389a36810SAnil Ravindranath { 88489a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; 88589a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 88689a36810SAnil Ravindranath u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); 88789a36810SAnil Ravindranath 88889a36810SAnil Ravindranath if (PMCRAID_IOASC_SENSE_KEY(ioasc) > 0) { 88989a36810SAnil Ravindranath scsi_cmd->result |= (DID_ERROR << 16); 89034876402SAnil Ravindranath scmd_printk(KERN_INFO, scsi_cmd, 89134876402SAnil Ravindranath "command CDB[0] = %x failed with IOASC: 0x%08X\n", 89289a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], ioasc); 89389a36810SAnil Ravindranath } 89489a36810SAnil Ravindranath 89589a36810SAnil Ravindranath /* if we had allocated sense buffers for request sense, copy the sense 89689a36810SAnil Ravindranath * release the buffers 89789a36810SAnil Ravindranath */ 89889a36810SAnil Ravindranath if (cmd->sense_buffer != NULL) { 89989a36810SAnil Ravindranath memcpy(scsi_cmd->sense_buffer, 90089a36810SAnil Ravindranath cmd->sense_buffer, 90189a36810SAnil Ravindranath SCSI_SENSE_BUFFERSIZE); 90289a36810SAnil Ravindranath pci_free_consistent(pinstance->pdev, 90389a36810SAnil Ravindranath SCSI_SENSE_BUFFERSIZE, 90489a36810SAnil Ravindranath cmd->sense_buffer, cmd->sense_buffer_dma); 90589a36810SAnil Ravindranath cmd->sense_buffer = NULL; 90689a36810SAnil Ravindranath cmd->sense_buffer_dma = 0; 90789a36810SAnil Ravindranath } 90889a36810SAnil Ravindranath 90989a36810SAnil Ravindranath scsi_dma_unmap(scsi_cmd); 91089a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 91189a36810SAnil Ravindranath scsi_cmd->scsi_done(scsi_cmd); 91289a36810SAnil Ravindranath } 91389a36810SAnil Ravindranath 91489a36810SAnil Ravindranath /** 91589a36810SAnil Ravindranath * pmcraid_fire_command - sends an IOA command to adapter 91689a36810SAnil Ravindranath * 91789a36810SAnil Ravindranath * This function adds the given block into pending command list 91889a36810SAnil Ravindranath * and returns without waiting 91989a36810SAnil Ravindranath * 92089a36810SAnil Ravindranath * @cmd : command to be sent to the device 92189a36810SAnil Ravindranath * 92289a36810SAnil Ravindranath * Return Value 92389a36810SAnil Ravindranath * None 92489a36810SAnil Ravindranath */ 92589a36810SAnil Ravindranath static void _pmcraid_fire_command(struct pmcraid_cmd *cmd) 92689a36810SAnil Ravindranath { 92789a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 92889a36810SAnil Ravindranath unsigned long lock_flags; 92989a36810SAnil Ravindranath 93089a36810SAnil Ravindranath /* Add this command block to pending cmd pool. We do this prior to 93189a36810SAnil Ravindranath * writting IOARCB to ioarrin because IOA might complete the command 93289a36810SAnil Ravindranath * by the time we are about to add it to the list. Response handler 933c20c4267SAnil Ravindranath * (isr/tasklet) looks for cmd block in the pending pending list. 93489a36810SAnil Ravindranath */ 93589a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->pending_pool_lock, lock_flags); 93689a36810SAnil Ravindranath list_add_tail(&cmd->free_list, &pinstance->pending_cmd_pool); 93789a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->pending_pool_lock, lock_flags); 93889a36810SAnil Ravindranath atomic_inc(&pinstance->outstanding_cmds); 93989a36810SAnil Ravindranath 94089a36810SAnil Ravindranath /* driver writes lower 32-bit value of IOARCB address only */ 94189a36810SAnil Ravindranath mb(); 94289a36810SAnil Ravindranath iowrite32(le32_to_cpu(cmd->ioa_cb->ioarcb.ioarcb_bus_addr), 94389a36810SAnil Ravindranath pinstance->ioarrin); 94489a36810SAnil Ravindranath } 94589a36810SAnil Ravindranath 94689a36810SAnil Ravindranath /** 94789a36810SAnil Ravindranath * pmcraid_send_cmd - fires a command to IOA 94889a36810SAnil Ravindranath * 94989a36810SAnil Ravindranath * This function also sets up timeout function, and command completion 95089a36810SAnil Ravindranath * function 95189a36810SAnil Ravindranath * 95289a36810SAnil Ravindranath * @cmd: pointer to the command block to be fired to IOA 95389a36810SAnil Ravindranath * @cmd_done: command completion function, called once IOA responds 95489a36810SAnil Ravindranath * @timeout: timeout to wait for this command completion 95589a36810SAnil Ravindranath * @timeout_func: timeout handler 95689a36810SAnil Ravindranath * 95789a36810SAnil Ravindranath * Return value 95889a36810SAnil Ravindranath * none 95989a36810SAnil Ravindranath */ 96089a36810SAnil Ravindranath static void pmcraid_send_cmd( 96189a36810SAnil Ravindranath struct pmcraid_cmd *cmd, 96289a36810SAnil Ravindranath void (*cmd_done) (struct pmcraid_cmd *), 96389a36810SAnil Ravindranath unsigned long timeout, 96489a36810SAnil Ravindranath void (*timeout_func) (struct pmcraid_cmd *) 96589a36810SAnil Ravindranath ) 96689a36810SAnil Ravindranath { 96789a36810SAnil Ravindranath /* initialize done function */ 96889a36810SAnil Ravindranath cmd->cmd_done = cmd_done; 96989a36810SAnil Ravindranath 97089a36810SAnil Ravindranath if (timeout_func) { 97189a36810SAnil Ravindranath /* setup timeout handler */ 97289a36810SAnil Ravindranath cmd->timer.data = (unsigned long)cmd; 97389a36810SAnil Ravindranath cmd->timer.expires = jiffies + timeout; 97489a36810SAnil Ravindranath cmd->timer.function = (void (*)(unsigned long))timeout_func; 97589a36810SAnil Ravindranath add_timer(&cmd->timer); 97689a36810SAnil Ravindranath } 97789a36810SAnil Ravindranath 97889a36810SAnil Ravindranath /* fire the command to IOA */ 97989a36810SAnil Ravindranath _pmcraid_fire_command(cmd); 98089a36810SAnil Ravindranath } 98189a36810SAnil Ravindranath 98289a36810SAnil Ravindranath /** 983c20c4267SAnil Ravindranath * pmcraid_ioa_shutdown_done - completion function for IOA shutdown command 984c20c4267SAnil Ravindranath * @cmd: pointer to the command block used for sending IOA shutdown command 985c20c4267SAnil Ravindranath * 986c20c4267SAnil Ravindranath * Return value 987c20c4267SAnil Ravindranath * None 988c20c4267SAnil Ravindranath */ 989c20c4267SAnil Ravindranath static void pmcraid_ioa_shutdown_done(struct pmcraid_cmd *cmd) 990c20c4267SAnil Ravindranath { 991c20c4267SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 992c20c4267SAnil Ravindranath unsigned long lock_flags; 993c20c4267SAnil Ravindranath 994c20c4267SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 995c20c4267SAnil Ravindranath pmcraid_ioa_reset(cmd); 996c20c4267SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 997c20c4267SAnil Ravindranath } 998c20c4267SAnil Ravindranath 999c20c4267SAnil Ravindranath /** 100089a36810SAnil Ravindranath * pmcraid_ioa_shutdown - sends SHUTDOWN command to ioa 100189a36810SAnil Ravindranath * 100289a36810SAnil Ravindranath * @cmd: pointer to the command block used as part of reset sequence 100389a36810SAnil Ravindranath * 100489a36810SAnil Ravindranath * Return Value 100589a36810SAnil Ravindranath * None 100689a36810SAnil Ravindranath */ 100789a36810SAnil Ravindranath static void pmcraid_ioa_shutdown(struct pmcraid_cmd *cmd) 100889a36810SAnil Ravindranath { 100989a36810SAnil Ravindranath pmcraid_info("response for Cancel CCN CDB[0] = %x ioasc = %x\n", 101089a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 101189a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)); 101289a36810SAnil Ravindranath 101389a36810SAnil Ravindranath /* Note that commands sent during reset require next command to be sent 101489a36810SAnil Ravindranath * to IOA. Hence reinit the done function as well as timeout function 101589a36810SAnil Ravindranath */ 101689a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 101789a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.request_type = REQ_TYPE_IOACMD; 101889a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.resource_handle = 101989a36810SAnil Ravindranath cpu_to_le32(PMCRAID_IOA_RES_HANDLE); 102089a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0] = PMCRAID_IOA_SHUTDOWN; 102189a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[1] = PMCRAID_SHUTDOWN_NORMAL; 102289a36810SAnil Ravindranath 102389a36810SAnil Ravindranath /* fire shutdown command to hardware. */ 102489a36810SAnil Ravindranath pmcraid_info("firing normal shutdown command (%d) to IOA\n", 102589a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle)); 102689a36810SAnil Ravindranath 1027c20c4267SAnil Ravindranath pmcraid_notify_ioastate(cmd->drv_inst, PMC_DEVICE_EVENT_SHUTDOWN_START); 1028c20c4267SAnil Ravindranath 1029c20c4267SAnil Ravindranath pmcraid_send_cmd(cmd, pmcraid_ioa_shutdown_done, 103089a36810SAnil Ravindranath PMCRAID_SHUTDOWN_TIMEOUT, 103189a36810SAnil Ravindranath pmcraid_timeout_handler); 103289a36810SAnil Ravindranath } 103389a36810SAnil Ravindranath 103489a36810SAnil Ravindranath /** 1035c20c4267SAnil Ravindranath * pmcraid_get_fwversion_done - completion function for get_fwversion 1036c20c4267SAnil Ravindranath * 1037c20c4267SAnil Ravindranath * @cmd: pointer to command block used to send INQUIRY command 1038c20c4267SAnil Ravindranath * 1039c20c4267SAnil Ravindranath * Return Value 1040c20c4267SAnil Ravindranath * none 1041c20c4267SAnil Ravindranath */ 1042c20c4267SAnil Ravindranath static void pmcraid_querycfg(struct pmcraid_cmd *); 1043c20c4267SAnil Ravindranath 1044c20c4267SAnil Ravindranath static void pmcraid_get_fwversion_done(struct pmcraid_cmd *cmd) 1045c20c4267SAnil Ravindranath { 1046c20c4267SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 1047c20c4267SAnil Ravindranath u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); 1048c20c4267SAnil Ravindranath unsigned long lock_flags; 1049c20c4267SAnil Ravindranath 1050c20c4267SAnil Ravindranath /* configuration table entry size depends on firmware version. If fw 1051c20c4267SAnil Ravindranath * version is not known, it is not possible to interpret IOA config 1052c20c4267SAnil Ravindranath * table 1053c20c4267SAnil Ravindranath */ 1054c20c4267SAnil Ravindranath if (ioasc) { 1055c20c4267SAnil Ravindranath pmcraid_err("IOA Inquiry failed with %x\n", ioasc); 1056c20c4267SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 1057c20c4267SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; 1058c20c4267SAnil Ravindranath pmcraid_reset_alert(cmd); 1059c20c4267SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 1060c20c4267SAnil Ravindranath } else { 1061c20c4267SAnil Ravindranath pmcraid_querycfg(cmd); 1062c20c4267SAnil Ravindranath } 1063c20c4267SAnil Ravindranath } 1064c20c4267SAnil Ravindranath 1065c20c4267SAnil Ravindranath /** 1066c20c4267SAnil Ravindranath * pmcraid_get_fwversion - reads firmware version information 1067c20c4267SAnil Ravindranath * 1068c20c4267SAnil Ravindranath * @cmd: pointer to command block used to send INQUIRY command 1069c20c4267SAnil Ravindranath * 1070c20c4267SAnil Ravindranath * Return Value 1071c20c4267SAnil Ravindranath * none 1072c20c4267SAnil Ravindranath */ 1073c20c4267SAnil Ravindranath static void pmcraid_get_fwversion(struct pmcraid_cmd *cmd) 1074c20c4267SAnil Ravindranath { 1075c20c4267SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 1076c20c4267SAnil Ravindranath struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; 1077c20c4267SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 1078c20c4267SAnil Ravindranath u16 data_size = sizeof(struct pmcraid_inquiry_data); 1079c20c4267SAnil Ravindranath 1080c20c4267SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 1081c20c4267SAnil Ravindranath ioarcb->request_type = REQ_TYPE_SCSI; 1082c20c4267SAnil Ravindranath ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); 1083c20c4267SAnil Ravindranath ioarcb->cdb[0] = INQUIRY; 1084c20c4267SAnil Ravindranath ioarcb->cdb[1] = 1; 1085c20c4267SAnil Ravindranath ioarcb->cdb[2] = 0xD0; 1086c20c4267SAnil Ravindranath ioarcb->cdb[3] = (data_size >> 8) & 0xFF; 1087c20c4267SAnil Ravindranath ioarcb->cdb[4] = data_size & 0xFF; 1088c20c4267SAnil Ravindranath 1089c20c4267SAnil Ravindranath /* Since entire inquiry data it can be part of IOARCB itself 1090c20c4267SAnil Ravindranath */ 1091c20c4267SAnil Ravindranath ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + 1092c20c4267SAnil Ravindranath offsetof(struct pmcraid_ioarcb, 1093c20c4267SAnil Ravindranath add_data.u.ioadl[0])); 1094c20c4267SAnil Ravindranath ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); 1095c20c4267SAnil Ravindranath ioarcb->ioarcb_bus_addr &= ~(0x1FULL); 1096c20c4267SAnil Ravindranath 1097c20c4267SAnil Ravindranath ioarcb->request_flags0 |= NO_LINK_DESCS; 1098c20c4267SAnil Ravindranath ioarcb->data_transfer_length = cpu_to_le32(data_size); 1099c20c4267SAnil Ravindranath ioadl = &(ioarcb->add_data.u.ioadl[0]); 1100c20c4267SAnil Ravindranath ioadl->flags = IOADL_FLAGS_LAST_DESC; 1101c20c4267SAnil Ravindranath ioadl->address = cpu_to_le64(pinstance->inq_data_baddr); 1102c20c4267SAnil Ravindranath ioadl->data_len = cpu_to_le32(data_size); 1103c20c4267SAnil Ravindranath 1104c20c4267SAnil Ravindranath pmcraid_send_cmd(cmd, pmcraid_get_fwversion_done, 1105c20c4267SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler); 1106c20c4267SAnil Ravindranath } 1107c20c4267SAnil Ravindranath 1108c20c4267SAnil Ravindranath /** 110989a36810SAnil Ravindranath * pmcraid_identify_hrrq - registers host rrq buffers with IOA 111089a36810SAnil Ravindranath * @cmd: pointer to command block to be used for identify hrrq 111189a36810SAnil Ravindranath * 111289a36810SAnil Ravindranath * Return Value 1113c20c4267SAnil Ravindranath * none 111489a36810SAnil Ravindranath */ 111589a36810SAnil Ravindranath static void pmcraid_identify_hrrq(struct pmcraid_cmd *cmd) 111689a36810SAnil Ravindranath { 111789a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 111889a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 1119c20c4267SAnil Ravindranath int index = cmd->hrrq_index; 112089a36810SAnil Ravindranath __be64 hrrq_addr = cpu_to_be64(pinstance->hrrq_start_bus_addr[index]); 112189a36810SAnil Ravindranath u32 hrrq_size = cpu_to_be32(sizeof(u32) * PMCRAID_MAX_CMD); 1122c20c4267SAnil Ravindranath void (*done_function)(struct pmcraid_cmd *); 112389a36810SAnil Ravindranath 112489a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 1125c20c4267SAnil Ravindranath cmd->hrrq_index = index + 1; 1126c20c4267SAnil Ravindranath 1127c20c4267SAnil Ravindranath if (cmd->hrrq_index < pinstance->num_hrrq) { 1128c20c4267SAnil Ravindranath done_function = pmcraid_identify_hrrq; 1129c20c4267SAnil Ravindranath } else { 1130c20c4267SAnil Ravindranath cmd->hrrq_index = 0; 1131c20c4267SAnil Ravindranath done_function = pmcraid_get_fwversion; 1132c20c4267SAnil Ravindranath } 113389a36810SAnil Ravindranath 113489a36810SAnil Ravindranath /* Initialize ioarcb */ 113589a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_IOACMD; 113689a36810SAnil Ravindranath ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); 113789a36810SAnil Ravindranath 113889a36810SAnil Ravindranath /* initialize the hrrq number where IOA will respond to this command */ 113989a36810SAnil Ravindranath ioarcb->hrrq_id = index; 114089a36810SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_IDENTIFY_HRRQ; 114189a36810SAnil Ravindranath ioarcb->cdb[1] = index; 114289a36810SAnil Ravindranath 114389a36810SAnil Ravindranath /* IOA expects 64-bit pci address to be written in B.E format 114489a36810SAnil Ravindranath * (i.e cdb[2]=MSByte..cdb[9]=LSB. 114589a36810SAnil Ravindranath */ 1146c20c4267SAnil Ravindranath pmcraid_info("HRRQ_IDENTIFY with hrrq:ioarcb:index => %llx:%llx:%x\n", 1147c20c4267SAnil Ravindranath hrrq_addr, ioarcb->ioarcb_bus_addr, index); 114889a36810SAnil Ravindranath 114989a36810SAnil Ravindranath memcpy(&(ioarcb->cdb[2]), &hrrq_addr, sizeof(hrrq_addr)); 115089a36810SAnil Ravindranath memcpy(&(ioarcb->cdb[10]), &hrrq_size, sizeof(hrrq_size)); 115189a36810SAnil Ravindranath 115289a36810SAnil Ravindranath /* Subsequent commands require HRRQ identification to be successful. 115389a36810SAnil Ravindranath * Note that this gets called even during reset from SCSI mid-layer 115489a36810SAnil Ravindranath * or tasklet 115589a36810SAnil Ravindranath */ 1156c20c4267SAnil Ravindranath pmcraid_send_cmd(cmd, done_function, 115789a36810SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, 115889a36810SAnil Ravindranath pmcraid_timeout_handler); 115989a36810SAnil Ravindranath } 116089a36810SAnil Ravindranath 116189a36810SAnil Ravindranath static void pmcraid_process_ccn(struct pmcraid_cmd *cmd); 116289a36810SAnil Ravindranath static void pmcraid_process_ldn(struct pmcraid_cmd *cmd); 116389a36810SAnil Ravindranath 116489a36810SAnil Ravindranath /** 116589a36810SAnil Ravindranath * pmcraid_send_hcam_cmd - send an initialized command block(HCAM) to IOA 116689a36810SAnil Ravindranath * 116789a36810SAnil Ravindranath * @cmd: initialized command block pointer 116889a36810SAnil Ravindranath * 116989a36810SAnil Ravindranath * Return Value 117089a36810SAnil Ravindranath * none 117189a36810SAnil Ravindranath */ 117289a36810SAnil Ravindranath static void pmcraid_send_hcam_cmd(struct pmcraid_cmd *cmd) 117389a36810SAnil Ravindranath { 117489a36810SAnil Ravindranath if (cmd->ioa_cb->ioarcb.cdb[1] == PMCRAID_HCAM_CODE_CONFIG_CHANGE) 117589a36810SAnil Ravindranath atomic_set(&(cmd->drv_inst->ccn.ignore), 0); 117689a36810SAnil Ravindranath else 117789a36810SAnil Ravindranath atomic_set(&(cmd->drv_inst->ldn.ignore), 0); 117889a36810SAnil Ravindranath 117989a36810SAnil Ravindranath pmcraid_send_cmd(cmd, cmd->cmd_done, 0, NULL); 118089a36810SAnil Ravindranath } 118189a36810SAnil Ravindranath 118289a36810SAnil Ravindranath /** 118389a36810SAnil Ravindranath * pmcraid_init_hcam - send an initialized command block(HCAM) to IOA 118489a36810SAnil Ravindranath * 118589a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 118689a36810SAnil Ravindranath * @type: HCAM type 118789a36810SAnil Ravindranath * 118889a36810SAnil Ravindranath * Return Value 118989a36810SAnil Ravindranath * pointer to initialized pmcraid_cmd structure or NULL 119089a36810SAnil Ravindranath */ 119189a36810SAnil Ravindranath static struct pmcraid_cmd *pmcraid_init_hcam 119289a36810SAnil Ravindranath ( 119389a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 119489a36810SAnil Ravindranath u8 type 119589a36810SAnil Ravindranath ) 119689a36810SAnil Ravindranath { 119789a36810SAnil Ravindranath struct pmcraid_cmd *cmd; 119889a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb; 119989a36810SAnil Ravindranath struct pmcraid_ioadl_desc *ioadl; 120089a36810SAnil Ravindranath struct pmcraid_hostrcb *hcam; 120189a36810SAnil Ravindranath void (*cmd_done) (struct pmcraid_cmd *); 120289a36810SAnil Ravindranath dma_addr_t dma; 120389a36810SAnil Ravindranath int rcb_size; 120489a36810SAnil Ravindranath 120589a36810SAnil Ravindranath cmd = pmcraid_get_free_cmd(pinstance); 120689a36810SAnil Ravindranath 120789a36810SAnil Ravindranath if (!cmd) { 120889a36810SAnil Ravindranath pmcraid_err("no free command blocks for hcam\n"); 120989a36810SAnil Ravindranath return cmd; 121089a36810SAnil Ravindranath } 121189a36810SAnil Ravindranath 121289a36810SAnil Ravindranath if (type == PMCRAID_HCAM_CODE_CONFIG_CHANGE) { 1213c20c4267SAnil Ravindranath rcb_size = sizeof(struct pmcraid_hcam_ccn_ext); 121489a36810SAnil Ravindranath cmd_done = pmcraid_process_ccn; 121589a36810SAnil Ravindranath dma = pinstance->ccn.baddr + PMCRAID_AEN_HDR_SIZE; 121689a36810SAnil Ravindranath hcam = &pinstance->ccn; 121789a36810SAnil Ravindranath } else { 121889a36810SAnil Ravindranath rcb_size = sizeof(struct pmcraid_hcam_ldn); 121989a36810SAnil Ravindranath cmd_done = pmcraid_process_ldn; 122089a36810SAnil Ravindranath dma = pinstance->ldn.baddr + PMCRAID_AEN_HDR_SIZE; 122189a36810SAnil Ravindranath hcam = &pinstance->ldn; 122289a36810SAnil Ravindranath } 122389a36810SAnil Ravindranath 122489a36810SAnil Ravindranath /* initialize command pointer used for HCAM registration */ 122589a36810SAnil Ravindranath hcam->cmd = cmd; 122689a36810SAnil Ravindranath 122789a36810SAnil Ravindranath ioarcb = &cmd->ioa_cb->ioarcb; 122889a36810SAnil Ravindranath ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + 122989a36810SAnil Ravindranath offsetof(struct pmcraid_ioarcb, 123089a36810SAnil Ravindranath add_data.u.ioadl[0])); 123189a36810SAnil Ravindranath ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); 123289a36810SAnil Ravindranath ioadl = ioarcb->add_data.u.ioadl; 123389a36810SAnil Ravindranath 123489a36810SAnil Ravindranath /* Initialize ioarcb */ 123589a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_HCAM; 123689a36810SAnil Ravindranath ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); 123789a36810SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_HOST_CONTROLLED_ASYNC; 123889a36810SAnil Ravindranath ioarcb->cdb[1] = type; 123989a36810SAnil Ravindranath ioarcb->cdb[7] = (rcb_size >> 8) & 0xFF; 124089a36810SAnil Ravindranath ioarcb->cdb[8] = (rcb_size) & 0xFF; 124189a36810SAnil Ravindranath 124289a36810SAnil Ravindranath ioarcb->data_transfer_length = cpu_to_le32(rcb_size); 124389a36810SAnil Ravindranath 124488197966SAnil Ravindranath ioadl[0].flags |= IOADL_FLAGS_READ_LAST; 124589a36810SAnil Ravindranath ioadl[0].data_len = cpu_to_le32(rcb_size); 124689a36810SAnil Ravindranath ioadl[0].address = cpu_to_le32(dma); 124789a36810SAnil Ravindranath 124889a36810SAnil Ravindranath cmd->cmd_done = cmd_done; 124989a36810SAnil Ravindranath return cmd; 125089a36810SAnil Ravindranath } 125189a36810SAnil Ravindranath 125289a36810SAnil Ravindranath /** 125389a36810SAnil Ravindranath * pmcraid_send_hcam - Send an HCAM to IOA 125489a36810SAnil Ravindranath * @pinstance: ioa config struct 125589a36810SAnil Ravindranath * @type: HCAM type 125689a36810SAnil Ravindranath * 125789a36810SAnil Ravindranath * This function will send a Host Controlled Async command to IOA. 125889a36810SAnil Ravindranath * 125989a36810SAnil Ravindranath * Return value: 126089a36810SAnil Ravindranath * none 126189a36810SAnil Ravindranath */ 126289a36810SAnil Ravindranath static void pmcraid_send_hcam(struct pmcraid_instance *pinstance, u8 type) 126389a36810SAnil Ravindranath { 126489a36810SAnil Ravindranath struct pmcraid_cmd *cmd = pmcraid_init_hcam(pinstance, type); 126589a36810SAnil Ravindranath pmcraid_send_hcam_cmd(cmd); 126689a36810SAnil Ravindranath } 126789a36810SAnil Ravindranath 126889a36810SAnil Ravindranath 126989a36810SAnil Ravindranath /** 127089a36810SAnil Ravindranath * pmcraid_prepare_cancel_cmd - prepares a command block to abort another 127189a36810SAnil Ravindranath * 127289a36810SAnil Ravindranath * @cmd: pointer to cmd that is used as cancelling command 127389a36810SAnil Ravindranath * @cmd_to_cancel: pointer to the command that needs to be cancelled 127489a36810SAnil Ravindranath */ 127589a36810SAnil Ravindranath static void pmcraid_prepare_cancel_cmd( 127689a36810SAnil Ravindranath struct pmcraid_cmd *cmd, 127789a36810SAnil Ravindranath struct pmcraid_cmd *cmd_to_cancel 127889a36810SAnil Ravindranath ) 127989a36810SAnil Ravindranath { 128089a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 128189a36810SAnil Ravindranath __be64 ioarcb_addr = cmd_to_cancel->ioa_cb->ioarcb.ioarcb_bus_addr; 128289a36810SAnil Ravindranath 128389a36810SAnil Ravindranath /* Get the resource handle to where the command to be aborted has been 128489a36810SAnil Ravindranath * sent. 128589a36810SAnil Ravindranath */ 128689a36810SAnil Ravindranath ioarcb->resource_handle = cmd_to_cancel->ioa_cb->ioarcb.resource_handle; 128789a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_IOACMD; 128889a36810SAnil Ravindranath memset(ioarcb->cdb, 0, PMCRAID_MAX_CDB_LEN); 128989a36810SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_ABORT_CMD; 129089a36810SAnil Ravindranath 129189a36810SAnil Ravindranath /* IOARCB address of the command to be cancelled is given in 129289a36810SAnil Ravindranath * cdb[2]..cdb[9] is Big-Endian format. Note that length bits in 129389a36810SAnil Ravindranath * IOARCB address are not masked. 129489a36810SAnil Ravindranath */ 129589a36810SAnil Ravindranath ioarcb_addr = cpu_to_be64(ioarcb_addr); 129689a36810SAnil Ravindranath memcpy(&(ioarcb->cdb[2]), &ioarcb_addr, sizeof(ioarcb_addr)); 129789a36810SAnil Ravindranath } 129889a36810SAnil Ravindranath 129989a36810SAnil Ravindranath /** 130089a36810SAnil Ravindranath * pmcraid_cancel_hcam - sends ABORT task to abort a given HCAM 130189a36810SAnil Ravindranath * 130289a36810SAnil Ravindranath * @cmd: command to be used as cancelling command 130389a36810SAnil Ravindranath * @type: HCAM type 130489a36810SAnil Ravindranath * @cmd_done: op done function for the cancelling command 130589a36810SAnil Ravindranath */ 130689a36810SAnil Ravindranath static void pmcraid_cancel_hcam( 130789a36810SAnil Ravindranath struct pmcraid_cmd *cmd, 130889a36810SAnil Ravindranath u8 type, 130989a36810SAnil Ravindranath void (*cmd_done) (struct pmcraid_cmd *) 131089a36810SAnil Ravindranath ) 131189a36810SAnil Ravindranath { 131289a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 131389a36810SAnil Ravindranath struct pmcraid_hostrcb *hcam; 131489a36810SAnil Ravindranath 131589a36810SAnil Ravindranath pinstance = cmd->drv_inst; 131689a36810SAnil Ravindranath hcam = (type == PMCRAID_HCAM_CODE_LOG_DATA) ? 131789a36810SAnil Ravindranath &pinstance->ldn : &pinstance->ccn; 131889a36810SAnil Ravindranath 131989a36810SAnil Ravindranath /* prepare for cancelling previous hcam command. If the HCAM is 132089a36810SAnil Ravindranath * currently not pending with IOA, we would have hcam->cmd as non-null 132189a36810SAnil Ravindranath */ 132289a36810SAnil Ravindranath if (hcam->cmd == NULL) 132389a36810SAnil Ravindranath return; 132489a36810SAnil Ravindranath 132589a36810SAnil Ravindranath pmcraid_prepare_cancel_cmd(cmd, hcam->cmd); 132689a36810SAnil Ravindranath 132789a36810SAnil Ravindranath /* writing to IOARRIN must be protected by host_lock, as mid-layer 132889a36810SAnil Ravindranath * schedule queuecommand while we are doing this 132989a36810SAnil Ravindranath */ 133089a36810SAnil Ravindranath pmcraid_send_cmd(cmd, cmd_done, 133189a36810SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, 133289a36810SAnil Ravindranath pmcraid_timeout_handler); 133389a36810SAnil Ravindranath } 133489a36810SAnil Ravindranath 133589a36810SAnil Ravindranath /** 133689a36810SAnil Ravindranath * pmcraid_cancel_ccn - cancel CCN HCAM already registered with IOA 133789a36810SAnil Ravindranath * 133889a36810SAnil Ravindranath * @cmd: command block to be used for cancelling the HCAM 133989a36810SAnil Ravindranath */ 134089a36810SAnil Ravindranath static void pmcraid_cancel_ccn(struct pmcraid_cmd *cmd) 134189a36810SAnil Ravindranath { 134289a36810SAnil Ravindranath pmcraid_info("response for Cancel LDN CDB[0] = %x ioasc = %x\n", 134389a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 134489a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)); 134589a36810SAnil Ravindranath 134689a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 134789a36810SAnil Ravindranath 134889a36810SAnil Ravindranath pmcraid_cancel_hcam(cmd, 134989a36810SAnil Ravindranath PMCRAID_HCAM_CODE_CONFIG_CHANGE, 135089a36810SAnil Ravindranath pmcraid_ioa_shutdown); 135189a36810SAnil Ravindranath } 135289a36810SAnil Ravindranath 135389a36810SAnil Ravindranath /** 135489a36810SAnil Ravindranath * pmcraid_cancel_ldn - cancel LDN HCAM already registered with IOA 135589a36810SAnil Ravindranath * 135689a36810SAnil Ravindranath * @cmd: command block to be used for cancelling the HCAM 135789a36810SAnil Ravindranath */ 135889a36810SAnil Ravindranath static void pmcraid_cancel_ldn(struct pmcraid_cmd *cmd) 135989a36810SAnil Ravindranath { 136089a36810SAnil Ravindranath pmcraid_cancel_hcam(cmd, 136189a36810SAnil Ravindranath PMCRAID_HCAM_CODE_LOG_DATA, 136289a36810SAnil Ravindranath pmcraid_cancel_ccn); 136389a36810SAnil Ravindranath } 136489a36810SAnil Ravindranath 136589a36810SAnil Ravindranath /** 136689a36810SAnil Ravindranath * pmcraid_expose_resource - check if the resource can be exposed to OS 136789a36810SAnil Ravindranath * 1368c20c4267SAnil Ravindranath * @fw_version: firmware version code 136989a36810SAnil Ravindranath * @cfgte: pointer to configuration table entry of the resource 137089a36810SAnil Ravindranath * 137189a36810SAnil Ravindranath * Return value: 137289a36810SAnil Ravindranath * true if resource can be added to midlayer, false(0) otherwise 137389a36810SAnil Ravindranath */ 1374c20c4267SAnil Ravindranath static int pmcraid_expose_resource(u16 fw_version, 1375c20c4267SAnil Ravindranath struct pmcraid_config_table_entry *cfgte) 137689a36810SAnil Ravindranath { 137789a36810SAnil Ravindranath int retval = 0; 137889a36810SAnil Ravindranath 1379c20c4267SAnil Ravindranath if (cfgte->resource_type == RES_TYPE_VSET) { 1380c20c4267SAnil Ravindranath if (fw_version <= PMCRAID_FW_VERSION_1) 1381729c8456SAnil Ravindranath retval = ((cfgte->unique_flags1 & 0x80) == 0); 1382c20c4267SAnil Ravindranath else 1383c20c4267SAnil Ravindranath retval = ((cfgte->unique_flags0 & 0x80) == 0 && 1384c20c4267SAnil Ravindranath (cfgte->unique_flags1 & 0x80) == 0); 1385c20c4267SAnil Ravindranath 1386c20c4267SAnil Ravindranath } else if (cfgte->resource_type == RES_TYPE_GSCSI) 138789a36810SAnil Ravindranath retval = (RES_BUS(cfgte->resource_address) != 138889a36810SAnil Ravindranath PMCRAID_VIRTUAL_ENCL_BUS_ID); 138989a36810SAnil Ravindranath return retval; 139089a36810SAnil Ravindranath } 139189a36810SAnil Ravindranath 139289a36810SAnil Ravindranath /* attributes supported by pmcraid_event_family */ 139389a36810SAnil Ravindranath enum { 139489a36810SAnil Ravindranath PMCRAID_AEN_ATTR_UNSPEC, 139589a36810SAnil Ravindranath PMCRAID_AEN_ATTR_EVENT, 139689a36810SAnil Ravindranath __PMCRAID_AEN_ATTR_MAX, 139789a36810SAnil Ravindranath }; 139889a36810SAnil Ravindranath #define PMCRAID_AEN_ATTR_MAX (__PMCRAID_AEN_ATTR_MAX - 1) 139989a36810SAnil Ravindranath 140089a36810SAnil Ravindranath /* commands supported by pmcraid_event_family */ 140189a36810SAnil Ravindranath enum { 140289a36810SAnil Ravindranath PMCRAID_AEN_CMD_UNSPEC, 140389a36810SAnil Ravindranath PMCRAID_AEN_CMD_EVENT, 140489a36810SAnil Ravindranath __PMCRAID_AEN_CMD_MAX, 140589a36810SAnil Ravindranath }; 140689a36810SAnil Ravindranath #define PMCRAID_AEN_CMD_MAX (__PMCRAID_AEN_CMD_MAX - 1) 140789a36810SAnil Ravindranath 140889a36810SAnil Ravindranath static struct genl_family pmcraid_event_family = { 140989a36810SAnil Ravindranath .id = GENL_ID_GENERATE, 141089a36810SAnil Ravindranath .name = "pmcraid", 141189a36810SAnil Ravindranath .version = 1, 141289a36810SAnil Ravindranath .maxattr = PMCRAID_AEN_ATTR_MAX 141389a36810SAnil Ravindranath }; 141489a36810SAnil Ravindranath 141589a36810SAnil Ravindranath /** 141689a36810SAnil Ravindranath * pmcraid_netlink_init - registers pmcraid_event_family 141789a36810SAnil Ravindranath * 141889a36810SAnil Ravindranath * Return value: 141989a36810SAnil Ravindranath * 0 if the pmcraid_event_family is successfully registered 142089a36810SAnil Ravindranath * with netlink generic, non-zero otherwise 142189a36810SAnil Ravindranath */ 142289a36810SAnil Ravindranath static int pmcraid_netlink_init(void) 142389a36810SAnil Ravindranath { 142489a36810SAnil Ravindranath int result; 142589a36810SAnil Ravindranath 142689a36810SAnil Ravindranath result = genl_register_family(&pmcraid_event_family); 142789a36810SAnil Ravindranath 142889a36810SAnil Ravindranath if (result) 142989a36810SAnil Ravindranath return result; 143089a36810SAnil Ravindranath 143189a36810SAnil Ravindranath pmcraid_info("registered NETLINK GENERIC group: %d\n", 143289a36810SAnil Ravindranath pmcraid_event_family.id); 143389a36810SAnil Ravindranath 143489a36810SAnil Ravindranath return result; 143589a36810SAnil Ravindranath } 143689a36810SAnil Ravindranath 143789a36810SAnil Ravindranath /** 143889a36810SAnil Ravindranath * pmcraid_netlink_release - unregisters pmcraid_event_family 143989a36810SAnil Ravindranath * 144089a36810SAnil Ravindranath * Return value: 144189a36810SAnil Ravindranath * none 144289a36810SAnil Ravindranath */ 144389a36810SAnil Ravindranath static void pmcraid_netlink_release(void) 144489a36810SAnil Ravindranath { 144589a36810SAnil Ravindranath genl_unregister_family(&pmcraid_event_family); 144689a36810SAnil Ravindranath } 144789a36810SAnil Ravindranath 144889a36810SAnil Ravindranath /** 144989a36810SAnil Ravindranath * pmcraid_notify_aen - sends event msg to user space application 145089a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 145189a36810SAnil Ravindranath * @type: HCAM type 145289a36810SAnil Ravindranath * 145389a36810SAnil Ravindranath * Return value: 145489a36810SAnil Ravindranath * 0 if success, error value in case of any failure. 145589a36810SAnil Ravindranath */ 1456c20c4267SAnil Ravindranath static int pmcraid_notify_aen( 1457c20c4267SAnil Ravindranath struct pmcraid_instance *pinstance, 1458c20c4267SAnil Ravindranath struct pmcraid_aen_msg *aen_msg, 1459c20c4267SAnil Ravindranath u32 data_size 1460c20c4267SAnil Ravindranath ) 146189a36810SAnil Ravindranath { 146289a36810SAnil Ravindranath struct sk_buff *skb; 146389a36810SAnil Ravindranath void *msg_header; 1464c20c4267SAnil Ravindranath u32 total_size, nla_genl_hdr_total_size; 146589a36810SAnil Ravindranath int result; 146689a36810SAnil Ravindranath 146789a36810SAnil Ravindranath aen_msg->hostno = (pinstance->host->unique_id << 16 | 146889a36810SAnil Ravindranath MINOR(pinstance->cdev.dev)); 146989a36810SAnil Ravindranath aen_msg->length = data_size; 1470c20c4267SAnil Ravindranath 147189a36810SAnil Ravindranath data_size += sizeof(*aen_msg); 147289a36810SAnil Ravindranath 147389a36810SAnil Ravindranath total_size = nla_total_size(data_size); 1474c20c4267SAnil Ravindranath /* Add GENL_HDR to total_size */ 1475c20c4267SAnil Ravindranath nla_genl_hdr_total_size = 1476c20c4267SAnil Ravindranath (total_size + (GENL_HDRLEN + 1477c20c4267SAnil Ravindranath ((struct genl_family *)&pmcraid_event_family)->hdrsize) 1478c20c4267SAnil Ravindranath + NLMSG_HDRLEN); 1479c20c4267SAnil Ravindranath skb = genlmsg_new(nla_genl_hdr_total_size, GFP_ATOMIC); 148089a36810SAnil Ravindranath 148189a36810SAnil Ravindranath 148289a36810SAnil Ravindranath if (!skb) { 148389a36810SAnil Ravindranath pmcraid_err("Failed to allocate aen data SKB of size: %x\n", 148489a36810SAnil Ravindranath total_size); 148589a36810SAnil Ravindranath return -ENOMEM; 148689a36810SAnil Ravindranath } 148789a36810SAnil Ravindranath 148889a36810SAnil Ravindranath /* add the genetlink message header */ 148989a36810SAnil Ravindranath msg_header = genlmsg_put(skb, 0, 0, 149089a36810SAnil Ravindranath &pmcraid_event_family, 0, 149189a36810SAnil Ravindranath PMCRAID_AEN_CMD_EVENT); 149289a36810SAnil Ravindranath if (!msg_header) { 149389a36810SAnil Ravindranath pmcraid_err("failed to copy command details\n"); 149489a36810SAnil Ravindranath nlmsg_free(skb); 149589a36810SAnil Ravindranath return -ENOMEM; 149689a36810SAnil Ravindranath } 149789a36810SAnil Ravindranath 149889a36810SAnil Ravindranath result = nla_put(skb, PMCRAID_AEN_ATTR_EVENT, data_size, aen_msg); 149989a36810SAnil Ravindranath 150089a36810SAnil Ravindranath if (result) { 150189a36810SAnil Ravindranath pmcraid_err("failed to copy AEN attribute data\n"); 150289a36810SAnil Ravindranath nlmsg_free(skb); 150389a36810SAnil Ravindranath return -EINVAL; 150489a36810SAnil Ravindranath } 150589a36810SAnil Ravindranath 150689a36810SAnil Ravindranath /* send genetlink multicast message to notify appplications */ 150789a36810SAnil Ravindranath result = genlmsg_end(skb, msg_header); 150889a36810SAnil Ravindranath 150989a36810SAnil Ravindranath if (result < 0) { 151089a36810SAnil Ravindranath pmcraid_err("genlmsg_end failed\n"); 151189a36810SAnil Ravindranath nlmsg_free(skb); 151289a36810SAnil Ravindranath return result; 151389a36810SAnil Ravindranath } 151489a36810SAnil Ravindranath 151589a36810SAnil Ravindranath result = 151689a36810SAnil Ravindranath genlmsg_multicast(skb, 0, pmcraid_event_family.id, GFP_ATOMIC); 151789a36810SAnil Ravindranath 151889a36810SAnil Ravindranath /* If there are no listeners, genlmsg_multicast may return non-zero 151989a36810SAnil Ravindranath * value. 152089a36810SAnil Ravindranath */ 152189a36810SAnil Ravindranath if (result) 1522c20c4267SAnil Ravindranath pmcraid_info("error (%x) sending aen event message\n", result); 152389a36810SAnil Ravindranath return result; 152489a36810SAnil Ravindranath } 152589a36810SAnil Ravindranath 152689a36810SAnil Ravindranath /** 1527c20c4267SAnil Ravindranath * pmcraid_notify_ccn - notifies about CCN event msg to user space 1528c20c4267SAnil Ravindranath * @pinstance: pointer adapter instance structure 1529c20c4267SAnil Ravindranath * 1530c20c4267SAnil Ravindranath * Return value: 1531c20c4267SAnil Ravindranath * 0 if success, error value in case of any failure 1532c20c4267SAnil Ravindranath */ 1533c20c4267SAnil Ravindranath static int pmcraid_notify_ccn(struct pmcraid_instance *pinstance) 1534c20c4267SAnil Ravindranath { 1535c20c4267SAnil Ravindranath return pmcraid_notify_aen(pinstance, 1536c20c4267SAnil Ravindranath pinstance->ccn.msg, 1537c20c4267SAnil Ravindranath pinstance->ccn.hcam->data_len + 1538c20c4267SAnil Ravindranath sizeof(struct pmcraid_hcam_hdr)); 1539c20c4267SAnil Ravindranath } 1540c20c4267SAnil Ravindranath 1541c20c4267SAnil Ravindranath /** 1542c20c4267SAnil Ravindranath * pmcraid_notify_ldn - notifies about CCN event msg to user space 1543c20c4267SAnil Ravindranath * @pinstance: pointer adapter instance structure 1544c20c4267SAnil Ravindranath * 1545c20c4267SAnil Ravindranath * Return value: 1546c20c4267SAnil Ravindranath * 0 if success, error value in case of any failure 1547c20c4267SAnil Ravindranath */ 1548c20c4267SAnil Ravindranath static int pmcraid_notify_ldn(struct pmcraid_instance *pinstance) 1549c20c4267SAnil Ravindranath { 1550c20c4267SAnil Ravindranath return pmcraid_notify_aen(pinstance, 1551c20c4267SAnil Ravindranath pinstance->ldn.msg, 1552c20c4267SAnil Ravindranath pinstance->ldn.hcam->data_len + 1553c20c4267SAnil Ravindranath sizeof(struct pmcraid_hcam_hdr)); 1554c20c4267SAnil Ravindranath } 1555c20c4267SAnil Ravindranath 1556c20c4267SAnil Ravindranath /** 1557c20c4267SAnil Ravindranath * pmcraid_notify_ioastate - sends IOA state event msg to user space 1558c20c4267SAnil Ravindranath * @pinstance: pointer adapter instance structure 1559c20c4267SAnil Ravindranath * @evt: controller state event to be sent 1560c20c4267SAnil Ravindranath * 1561c20c4267SAnil Ravindranath * Return value: 1562c20c4267SAnil Ravindranath * 0 if success, error value in case of any failure 1563c20c4267SAnil Ravindranath */ 1564c20c4267SAnil Ravindranath static void pmcraid_notify_ioastate(struct pmcraid_instance *pinstance, u32 evt) 1565c20c4267SAnil Ravindranath { 1566c20c4267SAnil Ravindranath pinstance->scn.ioa_state = evt; 1567c20c4267SAnil Ravindranath pmcraid_notify_aen(pinstance, 1568c20c4267SAnil Ravindranath &pinstance->scn.msg, 1569c20c4267SAnil Ravindranath sizeof(u32)); 1570c20c4267SAnil Ravindranath } 1571c20c4267SAnil Ravindranath 1572c20c4267SAnil Ravindranath /** 157389a36810SAnil Ravindranath * pmcraid_handle_config_change - Handle a config change from the adapter 157489a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 157589a36810SAnil Ravindranath * 157689a36810SAnil Ravindranath * Return value: 157789a36810SAnil Ravindranath * none 157889a36810SAnil Ravindranath */ 1579729c8456SAnil Ravindranath 158089a36810SAnil Ravindranath static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance) 158189a36810SAnil Ravindranath { 158289a36810SAnil Ravindranath struct pmcraid_config_table_entry *cfg_entry; 158389a36810SAnil Ravindranath struct pmcraid_hcam_ccn *ccn_hcam; 158489a36810SAnil Ravindranath struct pmcraid_cmd *cmd; 158589a36810SAnil Ravindranath struct pmcraid_cmd *cfgcmd; 158689a36810SAnil Ravindranath struct pmcraid_resource_entry *res = NULL; 158789a36810SAnil Ravindranath unsigned long lock_flags; 158889a36810SAnil Ravindranath unsigned long host_lock_flags; 1589729c8456SAnil Ravindranath u32 new_entry = 1; 1590729c8456SAnil Ravindranath u32 hidden_entry = 0; 1591c20c4267SAnil Ravindranath u16 fw_version; 159289a36810SAnil Ravindranath int rc; 159389a36810SAnil Ravindranath 159489a36810SAnil Ravindranath ccn_hcam = (struct pmcraid_hcam_ccn *)pinstance->ccn.hcam; 159589a36810SAnil Ravindranath cfg_entry = &ccn_hcam->cfg_entry; 1596c20c4267SAnil Ravindranath fw_version = be16_to_cpu(pinstance->inq_data->fw_version); 159789a36810SAnil Ravindranath 1598592488a3SAnil Ravindranath pmcraid_info("CCN(%x): %x timestamp: %llx type: %x lost: %x flags: %x \ 1599592488a3SAnil Ravindranath res: %x:%x:%x:%x\n", 160089a36810SAnil Ravindranath pinstance->ccn.hcam->ilid, 160189a36810SAnil Ravindranath pinstance->ccn.hcam->op_code, 1602592488a3SAnil Ravindranath ((pinstance->ccn.hcam->timestamp1) | 1603592488a3SAnil Ravindranath ((pinstance->ccn.hcam->timestamp2 & 0xffffffffLL) << 32)), 160489a36810SAnil Ravindranath pinstance->ccn.hcam->notification_type, 160589a36810SAnil Ravindranath pinstance->ccn.hcam->notification_lost, 160689a36810SAnil Ravindranath pinstance->ccn.hcam->flags, 160789a36810SAnil Ravindranath pinstance->host->unique_id, 160889a36810SAnil Ravindranath RES_IS_VSET(*cfg_entry) ? PMCRAID_VSET_BUS_ID : 160989a36810SAnil Ravindranath (RES_IS_GSCSI(*cfg_entry) ? PMCRAID_PHYS_BUS_ID : 161089a36810SAnil Ravindranath RES_BUS(cfg_entry->resource_address)), 1611c20c4267SAnil Ravindranath RES_IS_VSET(*cfg_entry) ? 1612c20c4267SAnil Ravindranath (fw_version <= PMCRAID_FW_VERSION_1 ? 1613c20c4267SAnil Ravindranath cfg_entry->unique_flags1 : 1614c20c4267SAnil Ravindranath cfg_entry->array_id & 0xFF) : 161589a36810SAnil Ravindranath RES_TARGET(cfg_entry->resource_address), 161689a36810SAnil Ravindranath RES_LUN(cfg_entry->resource_address)); 161789a36810SAnil Ravindranath 161889a36810SAnil Ravindranath 161989a36810SAnil Ravindranath /* If this HCAM indicates a lost notification, read the config table */ 162089a36810SAnil Ravindranath if (pinstance->ccn.hcam->notification_lost) { 162189a36810SAnil Ravindranath cfgcmd = pmcraid_get_free_cmd(pinstance); 162289a36810SAnil Ravindranath if (cfgcmd) { 162389a36810SAnil Ravindranath pmcraid_info("lost CCN, reading config table\b"); 162489a36810SAnil Ravindranath pinstance->reinit_cfg_table = 1; 162589a36810SAnil Ravindranath pmcraid_querycfg(cfgcmd); 162689a36810SAnil Ravindranath } else { 162789a36810SAnil Ravindranath pmcraid_err("lost CCN, no free cmd for querycfg\n"); 162889a36810SAnil Ravindranath } 162989a36810SAnil Ravindranath goto out_notify_apps; 163089a36810SAnil Ravindranath } 163189a36810SAnil Ravindranath 163289a36810SAnil Ravindranath /* If this resource is not going to be added to mid-layer, just notify 1633729c8456SAnil Ravindranath * applications and return. If this notification is about hiding a VSET 1634729c8456SAnil Ravindranath * resource, check if it was exposed already. 163589a36810SAnil Ravindranath */ 1636729c8456SAnil Ravindranath if (pinstance->ccn.hcam->notification_type == 1637729c8456SAnil Ravindranath NOTIFICATION_TYPE_ENTRY_CHANGED && 1638c20c4267SAnil Ravindranath cfg_entry->resource_type == RES_TYPE_VSET) { 1639c20c4267SAnil Ravindranath 1640c20c4267SAnil Ravindranath if (fw_version <= PMCRAID_FW_VERSION_1) 1641c20c4267SAnil Ravindranath hidden_entry = (cfg_entry->unique_flags1 & 0x80) != 0; 1642c20c4267SAnil Ravindranath else 1643c20c4267SAnil Ravindranath hidden_entry = (cfg_entry->unique_flags1 & 0x80) != 0; 1644c20c4267SAnil Ravindranath 1645c20c4267SAnil Ravindranath } else if (!pmcraid_expose_resource(fw_version, cfg_entry)) { 164689a36810SAnil Ravindranath goto out_notify_apps; 1647c20c4267SAnil Ravindranath } 164889a36810SAnil Ravindranath 164989a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->resource_lock, lock_flags); 165089a36810SAnil Ravindranath list_for_each_entry(res, &pinstance->used_res_q, queue) { 165189a36810SAnil Ravindranath rc = memcmp(&res->cfg_entry.resource_address, 165289a36810SAnil Ravindranath &cfg_entry->resource_address, 165389a36810SAnil Ravindranath sizeof(cfg_entry->resource_address)); 165489a36810SAnil Ravindranath if (!rc) { 165589a36810SAnil Ravindranath new_entry = 0; 165689a36810SAnil Ravindranath break; 165789a36810SAnil Ravindranath } 165889a36810SAnil Ravindranath } 165989a36810SAnil Ravindranath 166089a36810SAnil Ravindranath if (new_entry) { 166189a36810SAnil Ravindranath 1662729c8456SAnil Ravindranath if (hidden_entry) { 1663729c8456SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, 1664729c8456SAnil Ravindranath lock_flags); 1665729c8456SAnil Ravindranath goto out_notify_apps; 1666729c8456SAnil Ravindranath } 1667729c8456SAnil Ravindranath 166889a36810SAnil Ravindranath /* If there are more number of resources than what driver can 166989a36810SAnil Ravindranath * manage, do not notify the applications about the CCN. Just 167089a36810SAnil Ravindranath * ignore this notifications and re-register the same HCAM 167189a36810SAnil Ravindranath */ 167289a36810SAnil Ravindranath if (list_empty(&pinstance->free_res_q)) { 167389a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, 167489a36810SAnil Ravindranath lock_flags); 167589a36810SAnil Ravindranath pmcraid_err("too many resources attached\n"); 167689a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, 167789a36810SAnil Ravindranath host_lock_flags); 167889a36810SAnil Ravindranath pmcraid_send_hcam(pinstance, 167989a36810SAnil Ravindranath PMCRAID_HCAM_CODE_CONFIG_CHANGE); 168089a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 168189a36810SAnil Ravindranath host_lock_flags); 168289a36810SAnil Ravindranath return; 168389a36810SAnil Ravindranath } 168489a36810SAnil Ravindranath 168589a36810SAnil Ravindranath res = list_entry(pinstance->free_res_q.next, 168689a36810SAnil Ravindranath struct pmcraid_resource_entry, queue); 168789a36810SAnil Ravindranath 168889a36810SAnil Ravindranath list_del(&res->queue); 168989a36810SAnil Ravindranath res->scsi_dev = NULL; 169089a36810SAnil Ravindranath res->reset_progress = 0; 169189a36810SAnil Ravindranath list_add_tail(&res->queue, &pinstance->used_res_q); 169289a36810SAnil Ravindranath } 169389a36810SAnil Ravindranath 1694c20c4267SAnil Ravindranath memcpy(&res->cfg_entry, cfg_entry, pinstance->config_table_entry_size); 169589a36810SAnil Ravindranath 169689a36810SAnil Ravindranath if (pinstance->ccn.hcam->notification_type == 1697729c8456SAnil Ravindranath NOTIFICATION_TYPE_ENTRY_DELETED || hidden_entry) { 169889a36810SAnil Ravindranath if (res->scsi_dev) { 1699c20c4267SAnil Ravindranath if (fw_version <= PMCRAID_FW_VERSION_1) 1700729c8456SAnil Ravindranath res->cfg_entry.unique_flags1 &= 0x7F; 1701c20c4267SAnil Ravindranath else 1702c20c4267SAnil Ravindranath res->cfg_entry.array_id &= 0xFF; 170389a36810SAnil Ravindranath res->change_detected = RES_CHANGE_DEL; 170489a36810SAnil Ravindranath res->cfg_entry.resource_handle = 170589a36810SAnil Ravindranath PMCRAID_INVALID_RES_HANDLE; 170689a36810SAnil Ravindranath schedule_work(&pinstance->worker_q); 170789a36810SAnil Ravindranath } else { 170889a36810SAnil Ravindranath /* This may be one of the non-exposed resources */ 170989a36810SAnil Ravindranath list_move_tail(&res->queue, &pinstance->free_res_q); 171089a36810SAnil Ravindranath } 171189a36810SAnil Ravindranath } else if (!res->scsi_dev) { 171289a36810SAnil Ravindranath res->change_detected = RES_CHANGE_ADD; 171389a36810SAnil Ravindranath schedule_work(&pinstance->worker_q); 171489a36810SAnil Ravindranath } 171589a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); 171689a36810SAnil Ravindranath 171789a36810SAnil Ravindranath out_notify_apps: 171889a36810SAnil Ravindranath 171989a36810SAnil Ravindranath /* Notify configuration changes to registered applications.*/ 172089a36810SAnil Ravindranath if (!pmcraid_disable_aen) 1721c20c4267SAnil Ravindranath pmcraid_notify_ccn(pinstance); 172289a36810SAnil Ravindranath 172389a36810SAnil Ravindranath cmd = pmcraid_init_hcam(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE); 172489a36810SAnil Ravindranath if (cmd) 172589a36810SAnil Ravindranath pmcraid_send_hcam_cmd(cmd); 172689a36810SAnil Ravindranath } 172789a36810SAnil Ravindranath 172889a36810SAnil Ravindranath /** 172989a36810SAnil Ravindranath * pmcraid_get_error_info - return error string for an ioasc 173089a36810SAnil Ravindranath * @ioasc: ioasc code 173189a36810SAnil Ravindranath * Return Value 173289a36810SAnil Ravindranath * none 173389a36810SAnil Ravindranath */ 173489a36810SAnil Ravindranath static struct pmcraid_ioasc_error *pmcraid_get_error_info(u32 ioasc) 173589a36810SAnil Ravindranath { 173689a36810SAnil Ravindranath int i; 173789a36810SAnil Ravindranath for (i = 0; i < ARRAY_SIZE(pmcraid_ioasc_error_table); i++) { 173889a36810SAnil Ravindranath if (pmcraid_ioasc_error_table[i].ioasc_code == ioasc) 173989a36810SAnil Ravindranath return &pmcraid_ioasc_error_table[i]; 174089a36810SAnil Ravindranath } 174189a36810SAnil Ravindranath return NULL; 174289a36810SAnil Ravindranath } 174389a36810SAnil Ravindranath 174489a36810SAnil Ravindranath /** 174589a36810SAnil Ravindranath * pmcraid_ioasc_logger - log IOASC information based user-settings 174689a36810SAnil Ravindranath * @ioasc: ioasc code 174789a36810SAnil Ravindranath * @cmd: pointer to command that resulted in 'ioasc' 174889a36810SAnil Ravindranath */ 174989a36810SAnil Ravindranath void pmcraid_ioasc_logger(u32 ioasc, struct pmcraid_cmd *cmd) 175089a36810SAnil Ravindranath { 175189a36810SAnil Ravindranath struct pmcraid_ioasc_error *error_info = pmcraid_get_error_info(ioasc); 175289a36810SAnil Ravindranath 175389a36810SAnil Ravindranath if (error_info == NULL || 175489a36810SAnil Ravindranath cmd->drv_inst->current_log_level < error_info->log_level) 175589a36810SAnil Ravindranath return; 175689a36810SAnil Ravindranath 175789a36810SAnil Ravindranath /* log the error string */ 1758c20c4267SAnil Ravindranath pmcraid_err("cmd [%x] for resource %x failed with %x(%s)\n", 175989a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 176089a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.resource_handle, 176189a36810SAnil Ravindranath le32_to_cpu(ioasc), error_info->error_string); 176289a36810SAnil Ravindranath } 176389a36810SAnil Ravindranath 176489a36810SAnil Ravindranath /** 176589a36810SAnil Ravindranath * pmcraid_handle_error_log - Handle a config change (error log) from the IOA 176689a36810SAnil Ravindranath * 176789a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 176889a36810SAnil Ravindranath * 176989a36810SAnil Ravindranath * Return value: 177089a36810SAnil Ravindranath * none 177189a36810SAnil Ravindranath */ 177289a36810SAnil Ravindranath static void pmcraid_handle_error_log(struct pmcraid_instance *pinstance) 177389a36810SAnil Ravindranath { 177489a36810SAnil Ravindranath struct pmcraid_hcam_ldn *hcam_ldn; 177589a36810SAnil Ravindranath u32 ioasc; 177689a36810SAnil Ravindranath 177789a36810SAnil Ravindranath hcam_ldn = (struct pmcraid_hcam_ldn *)pinstance->ldn.hcam; 177889a36810SAnil Ravindranath 177989a36810SAnil Ravindranath pmcraid_info 178089a36810SAnil Ravindranath ("LDN(%x): %x type: %x lost: %x flags: %x overlay id: %x\n", 178189a36810SAnil Ravindranath pinstance->ldn.hcam->ilid, 178289a36810SAnil Ravindranath pinstance->ldn.hcam->op_code, 178389a36810SAnil Ravindranath pinstance->ldn.hcam->notification_type, 178489a36810SAnil Ravindranath pinstance->ldn.hcam->notification_lost, 178589a36810SAnil Ravindranath pinstance->ldn.hcam->flags, 178689a36810SAnil Ravindranath pinstance->ldn.hcam->overlay_id); 178789a36810SAnil Ravindranath 178889a36810SAnil Ravindranath /* log only the errors, no need to log informational log entries */ 178989a36810SAnil Ravindranath if (pinstance->ldn.hcam->notification_type != 179089a36810SAnil Ravindranath NOTIFICATION_TYPE_ERROR_LOG) 179189a36810SAnil Ravindranath return; 179289a36810SAnil Ravindranath 179389a36810SAnil Ravindranath if (pinstance->ldn.hcam->notification_lost == 179489a36810SAnil Ravindranath HOSTRCB_NOTIFICATIONS_LOST) 179534876402SAnil Ravindranath dev_info(&pinstance->pdev->dev, "Error notifications lost\n"); 179689a36810SAnil Ravindranath 179789a36810SAnil Ravindranath ioasc = le32_to_cpu(hcam_ldn->error_log.fd_ioasc); 179889a36810SAnil Ravindranath 179989a36810SAnil Ravindranath if (ioasc == PMCRAID_IOASC_UA_BUS_WAS_RESET || 180089a36810SAnil Ravindranath ioasc == PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER) { 180134876402SAnil Ravindranath dev_info(&pinstance->pdev->dev, 180289a36810SAnil Ravindranath "UnitAttention due to IOA Bus Reset\n"); 180389a36810SAnil Ravindranath scsi_report_bus_reset( 180489a36810SAnil Ravindranath pinstance->host, 180589a36810SAnil Ravindranath RES_BUS(hcam_ldn->error_log.fd_ra)); 180689a36810SAnil Ravindranath } 180789a36810SAnil Ravindranath 180889a36810SAnil Ravindranath return; 180989a36810SAnil Ravindranath } 181089a36810SAnil Ravindranath 181189a36810SAnil Ravindranath /** 181289a36810SAnil Ravindranath * pmcraid_process_ccn - Op done function for a CCN. 181389a36810SAnil Ravindranath * @cmd: pointer to command struct 181489a36810SAnil Ravindranath * 181589a36810SAnil Ravindranath * This function is the op done function for a configuration 181689a36810SAnil Ravindranath * change notification 181789a36810SAnil Ravindranath * 181889a36810SAnil Ravindranath * Return value: 181989a36810SAnil Ravindranath * none 182089a36810SAnil Ravindranath */ 182189a36810SAnil Ravindranath static void pmcraid_process_ccn(struct pmcraid_cmd *cmd) 182289a36810SAnil Ravindranath { 182389a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 182489a36810SAnil Ravindranath u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); 182589a36810SAnil Ravindranath unsigned long lock_flags; 182689a36810SAnil Ravindranath 182789a36810SAnil Ravindranath pinstance->ccn.cmd = NULL; 182889a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 182989a36810SAnil Ravindranath 183089a36810SAnil Ravindranath /* If driver initiated IOA reset happened while this hcam was pending 183189a36810SAnil Ravindranath * with IOA, or IOA bringdown sequence is in progress, no need to 183289a36810SAnil Ravindranath * re-register the hcam 183389a36810SAnil Ravindranath */ 183489a36810SAnil Ravindranath if (ioasc == PMCRAID_IOASC_IOA_WAS_RESET || 183589a36810SAnil Ravindranath atomic_read(&pinstance->ccn.ignore) == 1) { 183689a36810SAnil Ravindranath return; 183789a36810SAnil Ravindranath } else if (ioasc) { 183834876402SAnil Ravindranath dev_info(&pinstance->pdev->dev, 183989a36810SAnil Ravindranath "Host RCB (CCN) failed with IOASC: 0x%08X\n", ioasc); 184089a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 184189a36810SAnil Ravindranath pmcraid_send_hcam(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE); 184289a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 184389a36810SAnil Ravindranath } else { 184489a36810SAnil Ravindranath pmcraid_handle_config_change(pinstance); 184589a36810SAnil Ravindranath } 184689a36810SAnil Ravindranath } 184789a36810SAnil Ravindranath 184889a36810SAnil Ravindranath /** 184989a36810SAnil Ravindranath * pmcraid_process_ldn - op done function for an LDN 185089a36810SAnil Ravindranath * @cmd: pointer to command block 185189a36810SAnil Ravindranath * 185289a36810SAnil Ravindranath * Return value 185389a36810SAnil Ravindranath * none 185489a36810SAnil Ravindranath */ 185589a36810SAnil Ravindranath static void pmcraid_initiate_reset(struct pmcraid_instance *); 1856592488a3SAnil Ravindranath static void pmcraid_set_timestamp(struct pmcraid_cmd *cmd); 185789a36810SAnil Ravindranath 185889a36810SAnil Ravindranath static void pmcraid_process_ldn(struct pmcraid_cmd *cmd) 185989a36810SAnil Ravindranath { 186089a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 186189a36810SAnil Ravindranath struct pmcraid_hcam_ldn *ldn_hcam = 186289a36810SAnil Ravindranath (struct pmcraid_hcam_ldn *)pinstance->ldn.hcam; 186389a36810SAnil Ravindranath u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); 186489a36810SAnil Ravindranath u32 fd_ioasc = le32_to_cpu(ldn_hcam->error_log.fd_ioasc); 186589a36810SAnil Ravindranath unsigned long lock_flags; 186689a36810SAnil Ravindranath 186789a36810SAnil Ravindranath /* return the command block back to freepool */ 186889a36810SAnil Ravindranath pinstance->ldn.cmd = NULL; 186989a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 187089a36810SAnil Ravindranath 187189a36810SAnil Ravindranath /* If driver initiated IOA reset happened while this hcam was pending 187289a36810SAnil Ravindranath * with IOA, no need to re-register the hcam as reset engine will do it 187389a36810SAnil Ravindranath * once reset sequence is complete 187489a36810SAnil Ravindranath */ 187589a36810SAnil Ravindranath if (ioasc == PMCRAID_IOASC_IOA_WAS_RESET || 187689a36810SAnil Ravindranath atomic_read(&pinstance->ccn.ignore) == 1) { 187789a36810SAnil Ravindranath return; 187889a36810SAnil Ravindranath } else if (!ioasc) { 187989a36810SAnil Ravindranath pmcraid_handle_error_log(pinstance); 188089a36810SAnil Ravindranath if (fd_ioasc == PMCRAID_IOASC_NR_IOA_RESET_REQUIRED) { 188189a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, 188289a36810SAnil Ravindranath lock_flags); 188389a36810SAnil Ravindranath pmcraid_initiate_reset(pinstance); 188489a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 188589a36810SAnil Ravindranath lock_flags); 188689a36810SAnil Ravindranath return; 188789a36810SAnil Ravindranath } 1888592488a3SAnil Ravindranath if (fd_ioasc == PMCRAID_IOASC_TIME_STAMP_OUT_OF_SYNC) { 1889592488a3SAnil Ravindranath pinstance->timestamp_error = 1; 1890592488a3SAnil Ravindranath pmcraid_set_timestamp(cmd); 1891592488a3SAnil Ravindranath } 189289a36810SAnil Ravindranath } else { 189334876402SAnil Ravindranath dev_info(&pinstance->pdev->dev, 189489a36810SAnil Ravindranath "Host RCB(LDN) failed with IOASC: 0x%08X\n", ioasc); 189589a36810SAnil Ravindranath } 189689a36810SAnil Ravindranath /* send netlink message for HCAM notification if enabled */ 189789a36810SAnil Ravindranath if (!pmcraid_disable_aen) 1898c20c4267SAnil Ravindranath pmcraid_notify_ldn(pinstance); 189989a36810SAnil Ravindranath 190089a36810SAnil Ravindranath cmd = pmcraid_init_hcam(pinstance, PMCRAID_HCAM_CODE_LOG_DATA); 190189a36810SAnil Ravindranath if (cmd) 190289a36810SAnil Ravindranath pmcraid_send_hcam_cmd(cmd); 190389a36810SAnil Ravindranath } 190489a36810SAnil Ravindranath 190589a36810SAnil Ravindranath /** 190689a36810SAnil Ravindranath * pmcraid_register_hcams - register HCAMs for CCN and LDN 190789a36810SAnil Ravindranath * 190889a36810SAnil Ravindranath * @pinstance: pointer per adapter instance structure 190989a36810SAnil Ravindranath * 191089a36810SAnil Ravindranath * Return Value 191189a36810SAnil Ravindranath * none 191289a36810SAnil Ravindranath */ 191389a36810SAnil Ravindranath static void pmcraid_register_hcams(struct pmcraid_instance *pinstance) 191489a36810SAnil Ravindranath { 191589a36810SAnil Ravindranath pmcraid_send_hcam(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE); 191689a36810SAnil Ravindranath pmcraid_send_hcam(pinstance, PMCRAID_HCAM_CODE_LOG_DATA); 191789a36810SAnil Ravindranath } 191889a36810SAnil Ravindranath 191989a36810SAnil Ravindranath /** 192089a36810SAnil Ravindranath * pmcraid_unregister_hcams - cancel HCAMs registered already 192189a36810SAnil Ravindranath * @cmd: pointer to command used as part of reset sequence 192289a36810SAnil Ravindranath */ 192389a36810SAnil Ravindranath static void pmcraid_unregister_hcams(struct pmcraid_cmd *cmd) 192489a36810SAnil Ravindranath { 192589a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 192689a36810SAnil Ravindranath 192789a36810SAnil Ravindranath /* During IOA bringdown, HCAM gets fired and tasklet proceeds with 192889a36810SAnil Ravindranath * handling hcam response though it is not necessary. In order to 192989a36810SAnil Ravindranath * prevent this, set 'ignore', so that bring-down sequence doesn't 193089a36810SAnil Ravindranath * re-send any more hcams 193189a36810SAnil Ravindranath */ 193289a36810SAnil Ravindranath atomic_set(&pinstance->ccn.ignore, 1); 193389a36810SAnil Ravindranath atomic_set(&pinstance->ldn.ignore, 1); 193489a36810SAnil Ravindranath 193589a36810SAnil Ravindranath /* If adapter reset was forced as part of runtime reset sequence, 1936c20c4267SAnil Ravindranath * start the reset sequence. Reset will be triggered even in case 1937c20c4267SAnil Ravindranath * IOA unit_check. 193889a36810SAnil Ravindranath */ 1939c20c4267SAnil Ravindranath if ((pinstance->force_ioa_reset && !pinstance->ioa_bringdown) || 1940c20c4267SAnil Ravindranath pinstance->ioa_unit_check) { 194189a36810SAnil Ravindranath pinstance->force_ioa_reset = 0; 1942c20c4267SAnil Ravindranath pinstance->ioa_unit_check = 0; 194389a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; 194489a36810SAnil Ravindranath pmcraid_reset_alert(cmd); 194589a36810SAnil Ravindranath return; 194689a36810SAnil Ravindranath } 194789a36810SAnil Ravindranath 194889a36810SAnil Ravindranath /* Driver tries to cancel HCAMs by sending ABORT TASK for each HCAM 194989a36810SAnil Ravindranath * one after the other. So CCN cancellation will be triggered by 195089a36810SAnil Ravindranath * pmcraid_cancel_ldn itself. 195189a36810SAnil Ravindranath */ 195289a36810SAnil Ravindranath pmcraid_cancel_ldn(cmd); 195389a36810SAnil Ravindranath } 195489a36810SAnil Ravindranath 195589a36810SAnil Ravindranath /** 195689a36810SAnil Ravindranath * pmcraid_reset_enable_ioa - re-enable IOA after a hard reset 195789a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 195889a36810SAnil Ravindranath * Return Value 195989a36810SAnil Ravindranath * 1 if TRANSITION_TO_OPERATIONAL is active, otherwise 0 196089a36810SAnil Ravindranath */ 196189a36810SAnil Ravindranath static void pmcraid_reinit_buffers(struct pmcraid_instance *); 196289a36810SAnil Ravindranath 196389a36810SAnil Ravindranath static int pmcraid_reset_enable_ioa(struct pmcraid_instance *pinstance) 196489a36810SAnil Ravindranath { 196589a36810SAnil Ravindranath u32 intrs; 196689a36810SAnil Ravindranath 196789a36810SAnil Ravindranath pmcraid_reinit_buffers(pinstance); 196889a36810SAnil Ravindranath intrs = pmcraid_read_interrupts(pinstance); 196989a36810SAnil Ravindranath 197089a36810SAnil Ravindranath pmcraid_enable_interrupts(pinstance, PMCRAID_PCI_INTERRUPTS); 197189a36810SAnil Ravindranath 197289a36810SAnil Ravindranath if (intrs & INTRS_TRANSITION_TO_OPERATIONAL) { 1973c20c4267SAnil Ravindranath if (!pinstance->interrupt_mode) { 197489a36810SAnil Ravindranath iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, 1975c20c4267SAnil Ravindranath pinstance->int_regs. 1976c20c4267SAnil Ravindranath ioa_host_interrupt_mask_reg); 197789a36810SAnil Ravindranath iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, 197889a36810SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_clr_reg); 1979c20c4267SAnil Ravindranath } 198089a36810SAnil Ravindranath return 1; 198189a36810SAnil Ravindranath } else { 198289a36810SAnil Ravindranath return 0; 198389a36810SAnil Ravindranath } 198489a36810SAnil Ravindranath } 198589a36810SAnil Ravindranath 198689a36810SAnil Ravindranath /** 198789a36810SAnil Ravindranath * pmcraid_soft_reset - performs a soft reset and makes IOA become ready 198889a36810SAnil Ravindranath * @cmd : pointer to reset command block 198989a36810SAnil Ravindranath * 199089a36810SAnil Ravindranath * Return Value 199189a36810SAnil Ravindranath * none 199289a36810SAnil Ravindranath */ 199389a36810SAnil Ravindranath static void pmcraid_soft_reset(struct pmcraid_cmd *cmd) 199489a36810SAnil Ravindranath { 199589a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 199689a36810SAnil Ravindranath u32 int_reg; 199789a36810SAnil Ravindranath u32 doorbell; 199889a36810SAnil Ravindranath 199989a36810SAnil Ravindranath /* There will be an interrupt when Transition to Operational bit is 200089a36810SAnil Ravindranath * set so tasklet would execute next reset task. The timeout handler 200189a36810SAnil Ravindranath * would re-initiate a reset 200289a36810SAnil Ravindranath */ 200389a36810SAnil Ravindranath cmd->cmd_done = pmcraid_ioa_reset; 200489a36810SAnil Ravindranath cmd->timer.data = (unsigned long)cmd; 200589a36810SAnil Ravindranath cmd->timer.expires = jiffies + 200689a36810SAnil Ravindranath msecs_to_jiffies(PMCRAID_TRANSOP_TIMEOUT); 200789a36810SAnil Ravindranath cmd->timer.function = (void (*)(unsigned long))pmcraid_timeout_handler; 200889a36810SAnil Ravindranath 200989a36810SAnil Ravindranath if (!timer_pending(&cmd->timer)) 201089a36810SAnil Ravindranath add_timer(&cmd->timer); 201189a36810SAnil Ravindranath 201289a36810SAnil Ravindranath /* Enable destructive diagnostics on IOA if it is not yet in 201389a36810SAnil Ravindranath * operational state 201489a36810SAnil Ravindranath */ 201589a36810SAnil Ravindranath doorbell = DOORBELL_RUNTIME_RESET | 201689a36810SAnil Ravindranath DOORBELL_ENABLE_DESTRUCTIVE_DIAGS; 201789a36810SAnil Ravindranath 2018c20c4267SAnil Ravindranath /* Since we do RESET_ALERT and Start BIST we have to again write 2019c20c4267SAnil Ravindranath * MSIX Doorbell to indicate the interrupt mode 2020c20c4267SAnil Ravindranath */ 2021c20c4267SAnil Ravindranath if (pinstance->interrupt_mode) { 2022c20c4267SAnil Ravindranath iowrite32(DOORBELL_INTR_MODE_MSIX, 2023c20c4267SAnil Ravindranath pinstance->int_regs.host_ioa_interrupt_reg); 2024c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.host_ioa_interrupt_reg); 2025c20c4267SAnil Ravindranath } 2026c20c4267SAnil Ravindranath 202789a36810SAnil Ravindranath iowrite32(doorbell, pinstance->int_regs.host_ioa_interrupt_reg); 2028c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.host_ioa_interrupt_reg), 202989a36810SAnil Ravindranath int_reg = ioread32(pinstance->int_regs.ioa_host_interrupt_reg); 2030c20c4267SAnil Ravindranath 203189a36810SAnil Ravindranath pmcraid_info("Waiting for IOA to become operational %x:%x\n", 203289a36810SAnil Ravindranath ioread32(pinstance->int_regs.host_ioa_interrupt_reg), 203389a36810SAnil Ravindranath int_reg); 203489a36810SAnil Ravindranath } 203589a36810SAnil Ravindranath 203689a36810SAnil Ravindranath /** 203789a36810SAnil Ravindranath * pmcraid_get_dump - retrieves IOA dump in case of Unit Check interrupt 203889a36810SAnil Ravindranath * 203989a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 204089a36810SAnil Ravindranath * 204189a36810SAnil Ravindranath * Return Value 204289a36810SAnil Ravindranath * none 204389a36810SAnil Ravindranath */ 204489a36810SAnil Ravindranath static void pmcraid_get_dump(struct pmcraid_instance *pinstance) 204589a36810SAnil Ravindranath { 204689a36810SAnil Ravindranath pmcraid_info("%s is not yet implemented\n", __func__); 204789a36810SAnil Ravindranath } 204889a36810SAnil Ravindranath 204989a36810SAnil Ravindranath /** 205089a36810SAnil Ravindranath * pmcraid_fail_outstanding_cmds - Fails all outstanding ops. 205189a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 205289a36810SAnil Ravindranath * 205389a36810SAnil Ravindranath * This function fails all outstanding ops. If they are submitted to IOA 205489a36810SAnil Ravindranath * already, it sends cancel all messages if IOA is still accepting IOARCBs, 205589a36810SAnil Ravindranath * otherwise just completes the commands and returns the cmd blocks to free 205689a36810SAnil Ravindranath * pool. 205789a36810SAnil Ravindranath * 205889a36810SAnil Ravindranath * Return value: 205989a36810SAnil Ravindranath * none 206089a36810SAnil Ravindranath */ 206189a36810SAnil Ravindranath static void pmcraid_fail_outstanding_cmds(struct pmcraid_instance *pinstance) 206289a36810SAnil Ravindranath { 206389a36810SAnil Ravindranath struct pmcraid_cmd *cmd, *temp; 206489a36810SAnil Ravindranath unsigned long lock_flags; 206589a36810SAnil Ravindranath 206689a36810SAnil Ravindranath /* pending command list is protected by pending_pool_lock. Its 206789a36810SAnil Ravindranath * traversal must be done as within this lock 206889a36810SAnil Ravindranath */ 206989a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->pending_pool_lock, lock_flags); 207089a36810SAnil Ravindranath list_for_each_entry_safe(cmd, temp, &pinstance->pending_cmd_pool, 207189a36810SAnil Ravindranath free_list) { 207289a36810SAnil Ravindranath list_del(&cmd->free_list); 207389a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->pending_pool_lock, 207489a36810SAnil Ravindranath lock_flags); 207589a36810SAnil Ravindranath cmd->ioa_cb->ioasa.ioasc = 207689a36810SAnil Ravindranath cpu_to_le32(PMCRAID_IOASC_IOA_WAS_RESET); 207789a36810SAnil Ravindranath cmd->ioa_cb->ioasa.ilid = 207889a36810SAnil Ravindranath cpu_to_be32(PMCRAID_DRIVER_ILID); 207989a36810SAnil Ravindranath 208089a36810SAnil Ravindranath /* In case the command timer is still running */ 208189a36810SAnil Ravindranath del_timer(&cmd->timer); 208289a36810SAnil Ravindranath 208389a36810SAnil Ravindranath /* If this is an IO command, complete it by invoking scsi_done 208489a36810SAnil Ravindranath * function. If this is one of the internal commands other 208589a36810SAnil Ravindranath * than pmcraid_ioa_reset and HCAM commands invoke cmd_done to 208689a36810SAnil Ravindranath * complete it 208789a36810SAnil Ravindranath */ 208889a36810SAnil Ravindranath if (cmd->scsi_cmd) { 208989a36810SAnil Ravindranath 209089a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; 209189a36810SAnil Ravindranath __le32 resp = cmd->ioa_cb->ioarcb.response_handle; 209289a36810SAnil Ravindranath 209389a36810SAnil Ravindranath scsi_cmd->result |= DID_ERROR << 16; 209489a36810SAnil Ravindranath 209589a36810SAnil Ravindranath scsi_dma_unmap(scsi_cmd); 209689a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 209789a36810SAnil Ravindranath 209889a36810SAnil Ravindranath pmcraid_info("failing(%d) CDB[0] = %x result: %x\n", 209989a36810SAnil Ravindranath le32_to_cpu(resp) >> 2, 210089a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 210189a36810SAnil Ravindranath scsi_cmd->result); 210289a36810SAnil Ravindranath scsi_cmd->scsi_done(scsi_cmd); 210389a36810SAnil Ravindranath } else if (cmd->cmd_done == pmcraid_internal_done || 210489a36810SAnil Ravindranath cmd->cmd_done == pmcraid_erp_done) { 210589a36810SAnil Ravindranath cmd->cmd_done(cmd); 2106c20c4267SAnil Ravindranath } else if (cmd->cmd_done != pmcraid_ioa_reset && 2107c20c4267SAnil Ravindranath cmd->cmd_done != pmcraid_ioa_shutdown_done) { 210889a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 210989a36810SAnil Ravindranath } 211089a36810SAnil Ravindranath 211189a36810SAnil Ravindranath atomic_dec(&pinstance->outstanding_cmds); 211289a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->pending_pool_lock, lock_flags); 211389a36810SAnil Ravindranath } 211489a36810SAnil Ravindranath 211589a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->pending_pool_lock, lock_flags); 211689a36810SAnil Ravindranath } 211789a36810SAnil Ravindranath 211889a36810SAnil Ravindranath /** 211989a36810SAnil Ravindranath * pmcraid_ioa_reset - Implementation of IOA reset logic 212089a36810SAnil Ravindranath * 212189a36810SAnil Ravindranath * @cmd: pointer to the cmd block to be used for entire reset process 212289a36810SAnil Ravindranath * 212389a36810SAnil Ravindranath * This function executes most of the steps required for IOA reset. This gets 212489a36810SAnil Ravindranath * called by user threads (modprobe/insmod/rmmod) timer, tasklet and midlayer's 212525985edcSLucas De Marchi * 'eh_' thread. Access to variables used for controlling the reset sequence is 212689a36810SAnil Ravindranath * synchronized using host lock. Various functions called during reset process 212789a36810SAnil Ravindranath * would make use of a single command block, pointer to which is also stored in 212889a36810SAnil Ravindranath * adapter instance structure. 212989a36810SAnil Ravindranath * 213089a36810SAnil Ravindranath * Return Value 213189a36810SAnil Ravindranath * None 213289a36810SAnil Ravindranath */ 213389a36810SAnil Ravindranath static void pmcraid_ioa_reset(struct pmcraid_cmd *cmd) 213489a36810SAnil Ravindranath { 213589a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 213689a36810SAnil Ravindranath u8 reset_complete = 0; 213789a36810SAnil Ravindranath 213889a36810SAnil Ravindranath pinstance->ioa_reset_in_progress = 1; 213989a36810SAnil Ravindranath 214089a36810SAnil Ravindranath if (pinstance->reset_cmd != cmd) { 214189a36810SAnil Ravindranath pmcraid_err("reset is called with different command block\n"); 214289a36810SAnil Ravindranath pinstance->reset_cmd = cmd; 214389a36810SAnil Ravindranath } 214489a36810SAnil Ravindranath 214589a36810SAnil Ravindranath pmcraid_info("reset_engine: state = %d, command = %p\n", 214689a36810SAnil Ravindranath pinstance->ioa_state, cmd); 214789a36810SAnil Ravindranath 214889a36810SAnil Ravindranath switch (pinstance->ioa_state) { 214989a36810SAnil Ravindranath 215089a36810SAnil Ravindranath case IOA_STATE_DEAD: 215189a36810SAnil Ravindranath /* If IOA is offline, whatever may be the reset reason, just 215289a36810SAnil Ravindranath * return. callers might be waiting on the reset wait_q, wake 215389a36810SAnil Ravindranath * up them 215489a36810SAnil Ravindranath */ 215589a36810SAnil Ravindranath pmcraid_err("IOA is offline no reset is possible\n"); 215689a36810SAnil Ravindranath reset_complete = 1; 215789a36810SAnil Ravindranath break; 215889a36810SAnil Ravindranath 215989a36810SAnil Ravindranath case IOA_STATE_IN_BRINGDOWN: 216089a36810SAnil Ravindranath /* we enter here, once ioa shutdown command is processed by IOA 216189a36810SAnil Ravindranath * Alert IOA for a possible reset. If reset alert fails, IOA 216289a36810SAnil Ravindranath * goes through hard-reset 216389a36810SAnil Ravindranath */ 216489a36810SAnil Ravindranath pmcraid_disable_interrupts(pinstance, ~0); 216589a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; 216689a36810SAnil Ravindranath pmcraid_reset_alert(cmd); 216789a36810SAnil Ravindranath break; 216889a36810SAnil Ravindranath 216989a36810SAnil Ravindranath case IOA_STATE_UNKNOWN: 217089a36810SAnil Ravindranath /* We may be called during probe or resume. Some pre-processing 217189a36810SAnil Ravindranath * is required for prior to reset 217289a36810SAnil Ravindranath */ 217389a36810SAnil Ravindranath scsi_block_requests(pinstance->host); 217489a36810SAnil Ravindranath 217589a36810SAnil Ravindranath /* If asked to reset while IOA was processing responses or 217689a36810SAnil Ravindranath * there are any error responses then IOA may require 217789a36810SAnil Ravindranath * hard-reset. 217889a36810SAnil Ravindranath */ 217989a36810SAnil Ravindranath if (pinstance->ioa_hard_reset == 0) { 218089a36810SAnil Ravindranath if (ioread32(pinstance->ioa_status) & 218189a36810SAnil Ravindranath INTRS_TRANSITION_TO_OPERATIONAL) { 218289a36810SAnil Ravindranath pmcraid_info("sticky bit set, bring-up\n"); 218389a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_BRINGUP; 218489a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 218589a36810SAnil Ravindranath pmcraid_identify_hrrq(cmd); 218689a36810SAnil Ravindranath } else { 218789a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_SOFT_RESET; 218889a36810SAnil Ravindranath pmcraid_soft_reset(cmd); 218989a36810SAnil Ravindranath } 219089a36810SAnil Ravindranath } else { 219189a36810SAnil Ravindranath /* Alert IOA of a possible reset and wait for critical 219289a36810SAnil Ravindranath * operation in progress bit to reset 219389a36810SAnil Ravindranath */ 219489a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; 219589a36810SAnil Ravindranath pmcraid_reset_alert(cmd); 219689a36810SAnil Ravindranath } 219789a36810SAnil Ravindranath break; 219889a36810SAnil Ravindranath 219989a36810SAnil Ravindranath case IOA_STATE_IN_RESET_ALERT: 220089a36810SAnil Ravindranath /* If critical operation in progress bit is reset or wait gets 220189a36810SAnil Ravindranath * timed out, reset proceeds with starting BIST on the IOA. 220289a36810SAnil Ravindranath * pmcraid_ioa_hard_reset keeps a count of reset attempts. If 220389a36810SAnil Ravindranath * they are 3 or more, reset engine marks IOA dead and returns 220489a36810SAnil Ravindranath */ 220589a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_HARD_RESET; 220689a36810SAnil Ravindranath pmcraid_start_bist(cmd); 220789a36810SAnil Ravindranath break; 220889a36810SAnil Ravindranath 220989a36810SAnil Ravindranath case IOA_STATE_IN_HARD_RESET: 221089a36810SAnil Ravindranath pinstance->ioa_reset_attempts++; 221189a36810SAnil Ravindranath 221289a36810SAnil Ravindranath /* retry reset if we haven't reached maximum allowed limit */ 221389a36810SAnil Ravindranath if (pinstance->ioa_reset_attempts > PMCRAID_RESET_ATTEMPTS) { 221489a36810SAnil Ravindranath pinstance->ioa_reset_attempts = 0; 221589a36810SAnil Ravindranath pmcraid_err("IOA didn't respond marking it as dead\n"); 221689a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_DEAD; 2217c20c4267SAnil Ravindranath 2218c20c4267SAnil Ravindranath if (pinstance->ioa_bringdown) 2219c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, 2220c20c4267SAnil Ravindranath PMC_DEVICE_EVENT_SHUTDOWN_FAILED); 2221c20c4267SAnil Ravindranath else 2222c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, 2223c20c4267SAnil Ravindranath PMC_DEVICE_EVENT_RESET_FAILED); 222489a36810SAnil Ravindranath reset_complete = 1; 222589a36810SAnil Ravindranath break; 222689a36810SAnil Ravindranath } 222789a36810SAnil Ravindranath 222889a36810SAnil Ravindranath /* Once either bist or pci reset is done, restore PCI config 222989a36810SAnil Ravindranath * space. If this fails, proceed with hard reset again 223089a36810SAnil Ravindranath */ 22311d3c16a8SJon Mason pci_restore_state(pinstance->pdev); 223289a36810SAnil Ravindranath 223389a36810SAnil Ravindranath /* fail all pending commands */ 223489a36810SAnil Ravindranath pmcraid_fail_outstanding_cmds(pinstance); 223589a36810SAnil Ravindranath 223689a36810SAnil Ravindranath /* check if unit check is active, if so extract dump */ 223789a36810SAnil Ravindranath if (pinstance->ioa_unit_check) { 223889a36810SAnil Ravindranath pmcraid_info("unit check is active\n"); 223989a36810SAnil Ravindranath pinstance->ioa_unit_check = 0; 224089a36810SAnil Ravindranath pmcraid_get_dump(pinstance); 224189a36810SAnil Ravindranath pinstance->ioa_reset_attempts--; 224289a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; 224389a36810SAnil Ravindranath pmcraid_reset_alert(cmd); 224489a36810SAnil Ravindranath break; 224589a36810SAnil Ravindranath } 224689a36810SAnil Ravindranath 224789a36810SAnil Ravindranath /* if the reset reason is to bring-down the ioa, we might be 224889a36810SAnil Ravindranath * done with the reset restore pci_config_space and complete 224989a36810SAnil Ravindranath * the reset 225089a36810SAnil Ravindranath */ 225189a36810SAnil Ravindranath if (pinstance->ioa_bringdown) { 225289a36810SAnil Ravindranath pmcraid_info("bringing down the adapter\n"); 225389a36810SAnil Ravindranath pinstance->ioa_shutdown_type = SHUTDOWN_NONE; 225489a36810SAnil Ravindranath pinstance->ioa_bringdown = 0; 225589a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_UNKNOWN; 2256c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, 2257c20c4267SAnil Ravindranath PMC_DEVICE_EVENT_SHUTDOWN_SUCCESS); 225889a36810SAnil Ravindranath reset_complete = 1; 225989a36810SAnil Ravindranath } else { 226089a36810SAnil Ravindranath /* bring-up IOA, so proceed with soft reset 226189a36810SAnil Ravindranath * Reinitialize hrrq_buffers and their indices also 226289a36810SAnil Ravindranath * enable interrupts after a pci_restore_state 226389a36810SAnil Ravindranath */ 226489a36810SAnil Ravindranath if (pmcraid_reset_enable_ioa(pinstance)) { 226589a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_BRINGUP; 226689a36810SAnil Ravindranath pmcraid_info("bringing up the adapter\n"); 226789a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 226889a36810SAnil Ravindranath pmcraid_identify_hrrq(cmd); 226989a36810SAnil Ravindranath } else { 227089a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_SOFT_RESET; 227189a36810SAnil Ravindranath pmcraid_soft_reset(cmd); 227289a36810SAnil Ravindranath } 227389a36810SAnil Ravindranath } 227489a36810SAnil Ravindranath break; 227589a36810SAnil Ravindranath 227689a36810SAnil Ravindranath case IOA_STATE_IN_SOFT_RESET: 227789a36810SAnil Ravindranath /* TRANSITION TO OPERATIONAL is on so start initialization 227889a36810SAnil Ravindranath * sequence 227989a36810SAnil Ravindranath */ 228089a36810SAnil Ravindranath pmcraid_info("In softreset proceeding with bring-up\n"); 228189a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_BRINGUP; 228289a36810SAnil Ravindranath 228389a36810SAnil Ravindranath /* Initialization commands start with HRRQ identification. From 228489a36810SAnil Ravindranath * now on tasklet completes most of the commands as IOA is up 228589a36810SAnil Ravindranath * and intrs are enabled 228689a36810SAnil Ravindranath */ 228789a36810SAnil Ravindranath pmcraid_identify_hrrq(cmd); 228889a36810SAnil Ravindranath break; 228989a36810SAnil Ravindranath 229089a36810SAnil Ravindranath case IOA_STATE_IN_BRINGUP: 229189a36810SAnil Ravindranath /* we are done with bringing up of IOA, change the ioa_state to 229289a36810SAnil Ravindranath * operational and wake up any waiters 229389a36810SAnil Ravindranath */ 229489a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_OPERATIONAL; 229589a36810SAnil Ravindranath reset_complete = 1; 229689a36810SAnil Ravindranath break; 229789a36810SAnil Ravindranath 229889a36810SAnil Ravindranath case IOA_STATE_OPERATIONAL: 229989a36810SAnil Ravindranath default: 230089a36810SAnil Ravindranath /* When IOA is operational and a reset is requested, check for 230189a36810SAnil Ravindranath * the reset reason. If reset is to bring down IOA, unregister 230289a36810SAnil Ravindranath * HCAMs and initiate shutdown; if adapter reset is forced then 230389a36810SAnil Ravindranath * restart reset sequence again 230489a36810SAnil Ravindranath */ 230589a36810SAnil Ravindranath if (pinstance->ioa_shutdown_type == SHUTDOWN_NONE && 230689a36810SAnil Ravindranath pinstance->force_ioa_reset == 0) { 2307c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, 2308c20c4267SAnil Ravindranath PMC_DEVICE_EVENT_RESET_SUCCESS); 230989a36810SAnil Ravindranath reset_complete = 1; 231089a36810SAnil Ravindranath } else { 231189a36810SAnil Ravindranath if (pinstance->ioa_shutdown_type != SHUTDOWN_NONE) 231289a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_BRINGDOWN; 231389a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 231489a36810SAnil Ravindranath pmcraid_unregister_hcams(cmd); 231589a36810SAnil Ravindranath } 231689a36810SAnil Ravindranath break; 231789a36810SAnil Ravindranath } 231889a36810SAnil Ravindranath 231989a36810SAnil Ravindranath /* reset will be completed if ioa_state is either DEAD or UNKNOWN or 232089a36810SAnil Ravindranath * OPERATIONAL. Reset all control variables used during reset, wake up 232189a36810SAnil Ravindranath * any waiting threads and let the SCSI mid-layer send commands. Note 232289a36810SAnil Ravindranath * that host_lock must be held before invoking scsi_report_bus_reset. 232389a36810SAnil Ravindranath */ 232489a36810SAnil Ravindranath if (reset_complete) { 232589a36810SAnil Ravindranath pinstance->ioa_reset_in_progress = 0; 232689a36810SAnil Ravindranath pinstance->ioa_reset_attempts = 0; 232789a36810SAnil Ravindranath pinstance->reset_cmd = NULL; 232889a36810SAnil Ravindranath pinstance->ioa_shutdown_type = SHUTDOWN_NONE; 232989a36810SAnil Ravindranath pinstance->ioa_bringdown = 0; 233089a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 233189a36810SAnil Ravindranath 233289a36810SAnil Ravindranath /* If target state is to bring up the adapter, proceed with 233389a36810SAnil Ravindranath * hcam registration and resource exposure to mid-layer. 233489a36810SAnil Ravindranath */ 233589a36810SAnil Ravindranath if (pinstance->ioa_state == IOA_STATE_OPERATIONAL) 233689a36810SAnil Ravindranath pmcraid_register_hcams(pinstance); 233789a36810SAnil Ravindranath 233889a36810SAnil Ravindranath wake_up_all(&pinstance->reset_wait_q); 233989a36810SAnil Ravindranath } 234089a36810SAnil Ravindranath 234189a36810SAnil Ravindranath return; 234289a36810SAnil Ravindranath } 234389a36810SAnil Ravindranath 234489a36810SAnil Ravindranath /** 234589a36810SAnil Ravindranath * pmcraid_initiate_reset - initiates reset sequence. This is called from 234689a36810SAnil Ravindranath * ISR/tasklet during error interrupts including IOA unit check. If reset 234789a36810SAnil Ravindranath * is already in progress, it just returns, otherwise initiates IOA reset 234889a36810SAnil Ravindranath * to bring IOA up to operational state. 234989a36810SAnil Ravindranath * 235089a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 235189a36810SAnil Ravindranath * 235289a36810SAnil Ravindranath * Return value 235389a36810SAnil Ravindranath * none 235489a36810SAnil Ravindranath */ 235589a36810SAnil Ravindranath static void pmcraid_initiate_reset(struct pmcraid_instance *pinstance) 235689a36810SAnil Ravindranath { 235789a36810SAnil Ravindranath struct pmcraid_cmd *cmd; 235889a36810SAnil Ravindranath 235989a36810SAnil Ravindranath /* If the reset is already in progress, just return, otherwise start 236089a36810SAnil Ravindranath * reset sequence and return 236189a36810SAnil Ravindranath */ 236289a36810SAnil Ravindranath if (!pinstance->ioa_reset_in_progress) { 236389a36810SAnil Ravindranath scsi_block_requests(pinstance->host); 236489a36810SAnil Ravindranath cmd = pmcraid_get_free_cmd(pinstance); 236589a36810SAnil Ravindranath 236689a36810SAnil Ravindranath if (cmd == NULL) { 236789a36810SAnil Ravindranath pmcraid_err("no cmnd blocks for initiate_reset\n"); 236889a36810SAnil Ravindranath return; 236989a36810SAnil Ravindranath } 237089a36810SAnil Ravindranath 237189a36810SAnil Ravindranath pinstance->ioa_shutdown_type = SHUTDOWN_NONE; 237289a36810SAnil Ravindranath pinstance->reset_cmd = cmd; 237389a36810SAnil Ravindranath pinstance->force_ioa_reset = 1; 2374c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, 2375c20c4267SAnil Ravindranath PMC_DEVICE_EVENT_RESET_START); 237689a36810SAnil Ravindranath pmcraid_ioa_reset(cmd); 237789a36810SAnil Ravindranath } 237889a36810SAnil Ravindranath } 237989a36810SAnil Ravindranath 238089a36810SAnil Ravindranath /** 238189a36810SAnil Ravindranath * pmcraid_reset_reload - utility routine for doing IOA reset either to bringup 238289a36810SAnil Ravindranath * or bringdown IOA 238389a36810SAnil Ravindranath * @pinstance: pointer adapter instance structure 238489a36810SAnil Ravindranath * @shutdown_type: shutdown type to be used NONE, NORMAL or ABRREV 238589a36810SAnil Ravindranath * @target_state: expected target state after reset 238689a36810SAnil Ravindranath * 238789a36810SAnil Ravindranath * Note: This command initiates reset and waits for its completion. Hence this 238889a36810SAnil Ravindranath * should not be called from isr/timer/tasklet functions (timeout handlers, 238989a36810SAnil Ravindranath * error response handlers and interrupt handlers). 239089a36810SAnil Ravindranath * 239189a36810SAnil Ravindranath * Return Value 239289a36810SAnil Ravindranath * 1 in case ioa_state is not target_state, 0 otherwise. 239389a36810SAnil Ravindranath */ 239489a36810SAnil Ravindranath static int pmcraid_reset_reload( 239589a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 239689a36810SAnil Ravindranath u8 shutdown_type, 239789a36810SAnil Ravindranath u8 target_state 239889a36810SAnil Ravindranath ) 239989a36810SAnil Ravindranath { 240089a36810SAnil Ravindranath struct pmcraid_cmd *reset_cmd = NULL; 240189a36810SAnil Ravindranath unsigned long lock_flags; 240289a36810SAnil Ravindranath int reset = 1; 240389a36810SAnil Ravindranath 240489a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 240589a36810SAnil Ravindranath 240689a36810SAnil Ravindranath if (pinstance->ioa_reset_in_progress) { 240789a36810SAnil Ravindranath pmcraid_info("reset_reload: reset is already in progress\n"); 240889a36810SAnil Ravindranath 240989a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 241089a36810SAnil Ravindranath 241189a36810SAnil Ravindranath wait_event(pinstance->reset_wait_q, 241289a36810SAnil Ravindranath !pinstance->ioa_reset_in_progress); 241389a36810SAnil Ravindranath 241489a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 241589a36810SAnil Ravindranath 241689a36810SAnil Ravindranath if (pinstance->ioa_state == IOA_STATE_DEAD) { 241789a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 241889a36810SAnil Ravindranath lock_flags); 241989a36810SAnil Ravindranath pmcraid_info("reset_reload: IOA is dead\n"); 242089a36810SAnil Ravindranath return reset; 242189a36810SAnil Ravindranath } else if (pinstance->ioa_state == target_state) { 242289a36810SAnil Ravindranath reset = 0; 242389a36810SAnil Ravindranath } 242489a36810SAnil Ravindranath } 242589a36810SAnil Ravindranath 242689a36810SAnil Ravindranath if (reset) { 242789a36810SAnil Ravindranath pmcraid_info("reset_reload: proceeding with reset\n"); 242889a36810SAnil Ravindranath scsi_block_requests(pinstance->host); 242989a36810SAnil Ravindranath reset_cmd = pmcraid_get_free_cmd(pinstance); 243089a36810SAnil Ravindranath 243189a36810SAnil Ravindranath if (reset_cmd == NULL) { 243289a36810SAnil Ravindranath pmcraid_err("no free cmnd for reset_reload\n"); 243389a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 243489a36810SAnil Ravindranath lock_flags); 243589a36810SAnil Ravindranath return reset; 243689a36810SAnil Ravindranath } 243789a36810SAnil Ravindranath 243889a36810SAnil Ravindranath if (shutdown_type == SHUTDOWN_NORMAL) 243989a36810SAnil Ravindranath pinstance->ioa_bringdown = 1; 244089a36810SAnil Ravindranath 244189a36810SAnil Ravindranath pinstance->ioa_shutdown_type = shutdown_type; 244289a36810SAnil Ravindranath pinstance->reset_cmd = reset_cmd; 244389a36810SAnil Ravindranath pinstance->force_ioa_reset = reset; 244489a36810SAnil Ravindranath pmcraid_info("reset_reload: initiating reset\n"); 244589a36810SAnil Ravindranath pmcraid_ioa_reset(reset_cmd); 244689a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 244789a36810SAnil Ravindranath pmcraid_info("reset_reload: waiting for reset to complete\n"); 244889a36810SAnil Ravindranath wait_event(pinstance->reset_wait_q, 244989a36810SAnil Ravindranath !pinstance->ioa_reset_in_progress); 245089a36810SAnil Ravindranath 245189a36810SAnil Ravindranath pmcraid_info("reset_reload: reset is complete !!\n"); 245289a36810SAnil Ravindranath scsi_unblock_requests(pinstance->host); 245389a36810SAnil Ravindranath if (pinstance->ioa_state == target_state) 245489a36810SAnil Ravindranath reset = 0; 245589a36810SAnil Ravindranath } 245689a36810SAnil Ravindranath 245789a36810SAnil Ravindranath return reset; 245889a36810SAnil Ravindranath } 245989a36810SAnil Ravindranath 246089a36810SAnil Ravindranath /** 246189a36810SAnil Ravindranath * pmcraid_reset_bringdown - wrapper over pmcraid_reset_reload to bringdown IOA 246289a36810SAnil Ravindranath * 246389a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 246489a36810SAnil Ravindranath * 246589a36810SAnil Ravindranath * Return Value 246689a36810SAnil Ravindranath * whatever is returned from pmcraid_reset_reload 246789a36810SAnil Ravindranath */ 246889a36810SAnil Ravindranath static int pmcraid_reset_bringdown(struct pmcraid_instance *pinstance) 246989a36810SAnil Ravindranath { 247089a36810SAnil Ravindranath return pmcraid_reset_reload(pinstance, 247189a36810SAnil Ravindranath SHUTDOWN_NORMAL, 247289a36810SAnil Ravindranath IOA_STATE_UNKNOWN); 247389a36810SAnil Ravindranath } 247489a36810SAnil Ravindranath 247589a36810SAnil Ravindranath /** 247689a36810SAnil Ravindranath * pmcraid_reset_bringup - wrapper over pmcraid_reset_reload to bring up IOA 247789a36810SAnil Ravindranath * 247889a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 247989a36810SAnil Ravindranath * 248089a36810SAnil Ravindranath * Return Value 248189a36810SAnil Ravindranath * whatever is returned from pmcraid_reset_reload 248289a36810SAnil Ravindranath */ 248389a36810SAnil Ravindranath static int pmcraid_reset_bringup(struct pmcraid_instance *pinstance) 248489a36810SAnil Ravindranath { 2485c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, PMC_DEVICE_EVENT_RESET_START); 2486c20c4267SAnil Ravindranath 248789a36810SAnil Ravindranath return pmcraid_reset_reload(pinstance, 248889a36810SAnil Ravindranath SHUTDOWN_NONE, 248989a36810SAnil Ravindranath IOA_STATE_OPERATIONAL); 249089a36810SAnil Ravindranath } 249189a36810SAnil Ravindranath 249289a36810SAnil Ravindranath /** 249389a36810SAnil Ravindranath * pmcraid_request_sense - Send request sense to a device 249489a36810SAnil Ravindranath * @cmd: pmcraid command struct 249589a36810SAnil Ravindranath * 249689a36810SAnil Ravindranath * This function sends a request sense to a device as a result of a check 249789a36810SAnil Ravindranath * condition. This method re-uses the same command block that failed earlier. 249889a36810SAnil Ravindranath */ 249989a36810SAnil Ravindranath static void pmcraid_request_sense(struct pmcraid_cmd *cmd) 250089a36810SAnil Ravindranath { 250189a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 250289a36810SAnil Ravindranath struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; 250389a36810SAnil Ravindranath 250489a36810SAnil Ravindranath /* allocate DMAable memory for sense buffers */ 250589a36810SAnil Ravindranath cmd->sense_buffer = pci_alloc_consistent(cmd->drv_inst->pdev, 250689a36810SAnil Ravindranath SCSI_SENSE_BUFFERSIZE, 250789a36810SAnil Ravindranath &cmd->sense_buffer_dma); 250889a36810SAnil Ravindranath 250989a36810SAnil Ravindranath if (cmd->sense_buffer == NULL) { 251089a36810SAnil Ravindranath pmcraid_err 251189a36810SAnil Ravindranath ("couldn't allocate sense buffer for request sense\n"); 251289a36810SAnil Ravindranath pmcraid_erp_done(cmd); 251389a36810SAnil Ravindranath return; 251489a36810SAnil Ravindranath } 251589a36810SAnil Ravindranath 251689a36810SAnil Ravindranath /* re-use the command block */ 251789a36810SAnil Ravindranath memset(&cmd->ioa_cb->ioasa, 0, sizeof(struct pmcraid_ioasa)); 251889a36810SAnil Ravindranath memset(ioarcb->cdb, 0, PMCRAID_MAX_CDB_LEN); 251989a36810SAnil Ravindranath ioarcb->request_flags0 = (SYNC_COMPLETE | 252089a36810SAnil Ravindranath NO_LINK_DESCS | 252189a36810SAnil Ravindranath INHIBIT_UL_CHECK); 252289a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_SCSI; 252389a36810SAnil Ravindranath ioarcb->cdb[0] = REQUEST_SENSE; 252489a36810SAnil Ravindranath ioarcb->cdb[4] = SCSI_SENSE_BUFFERSIZE; 252589a36810SAnil Ravindranath 252689a36810SAnil Ravindranath ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + 252789a36810SAnil Ravindranath offsetof(struct pmcraid_ioarcb, 252889a36810SAnil Ravindranath add_data.u.ioadl[0])); 252989a36810SAnil Ravindranath ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); 253089a36810SAnil Ravindranath 253189a36810SAnil Ravindranath ioarcb->data_transfer_length = cpu_to_le32(SCSI_SENSE_BUFFERSIZE); 253289a36810SAnil Ravindranath 253389a36810SAnil Ravindranath ioadl->address = cpu_to_le64(cmd->sense_buffer_dma); 253489a36810SAnil Ravindranath ioadl->data_len = cpu_to_le32(SCSI_SENSE_BUFFERSIZE); 253588197966SAnil Ravindranath ioadl->flags = IOADL_FLAGS_LAST_DESC; 253689a36810SAnil Ravindranath 253789a36810SAnil Ravindranath /* request sense might be called as part of error response processing 253889a36810SAnil Ravindranath * which runs in tasklets context. It is possible that mid-layer might 253989a36810SAnil Ravindranath * schedule queuecommand during this time, hence, writting to IOARRIN 254089a36810SAnil Ravindranath * must be protect by host_lock 254189a36810SAnil Ravindranath */ 254289a36810SAnil Ravindranath pmcraid_send_cmd(cmd, pmcraid_erp_done, 254389a36810SAnil Ravindranath PMCRAID_REQUEST_SENSE_TIMEOUT, 254489a36810SAnil Ravindranath pmcraid_timeout_handler); 254589a36810SAnil Ravindranath } 254689a36810SAnil Ravindranath 254789a36810SAnil Ravindranath /** 254889a36810SAnil Ravindranath * pmcraid_cancel_all - cancel all outstanding IOARCBs as part of error recovery 254989a36810SAnil Ravindranath * @cmd: command that failed 255089a36810SAnil Ravindranath * @sense: true if request_sense is required after cancel all 255189a36810SAnil Ravindranath * 255289a36810SAnil Ravindranath * This function sends a cancel all to a device to clear the queue. 255389a36810SAnil Ravindranath */ 255489a36810SAnil Ravindranath static void pmcraid_cancel_all(struct pmcraid_cmd *cmd, u32 sense) 255589a36810SAnil Ravindranath { 255689a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; 255789a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 255889a36810SAnil Ravindranath struct pmcraid_resource_entry *res = scsi_cmd->device->hostdata; 255989a36810SAnil Ravindranath void (*cmd_done) (struct pmcraid_cmd *) = sense ? pmcraid_erp_done 256089a36810SAnil Ravindranath : pmcraid_request_sense; 256189a36810SAnil Ravindranath 256289a36810SAnil Ravindranath memset(ioarcb->cdb, 0, PMCRAID_MAX_CDB_LEN); 256389a36810SAnil Ravindranath ioarcb->request_flags0 = SYNC_OVERRIDE; 256489a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_IOACMD; 256589a36810SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_CANCEL_ALL_REQUESTS; 256689a36810SAnil Ravindranath 256789a36810SAnil Ravindranath if (RES_IS_GSCSI(res->cfg_entry)) 256889a36810SAnil Ravindranath ioarcb->cdb[1] = PMCRAID_SYNC_COMPLETE_AFTER_CANCEL; 256989a36810SAnil Ravindranath 257089a36810SAnil Ravindranath ioarcb->ioadl_bus_addr = 0; 257189a36810SAnil Ravindranath ioarcb->ioadl_length = 0; 257289a36810SAnil Ravindranath ioarcb->data_transfer_length = 0; 257389a36810SAnil Ravindranath ioarcb->ioarcb_bus_addr &= (~0x1FULL); 257489a36810SAnil Ravindranath 257589a36810SAnil Ravindranath /* writing to IOARRIN must be protected by host_lock, as mid-layer 257689a36810SAnil Ravindranath * schedule queuecommand while we are doing this 257789a36810SAnil Ravindranath */ 257889a36810SAnil Ravindranath pmcraid_send_cmd(cmd, cmd_done, 257989a36810SAnil Ravindranath PMCRAID_REQUEST_SENSE_TIMEOUT, 258089a36810SAnil Ravindranath pmcraid_timeout_handler); 258189a36810SAnil Ravindranath } 258289a36810SAnil Ravindranath 258389a36810SAnil Ravindranath /** 258489a36810SAnil Ravindranath * pmcraid_frame_auto_sense: frame fixed format sense information 258589a36810SAnil Ravindranath * 258689a36810SAnil Ravindranath * @cmd: pointer to failing command block 258789a36810SAnil Ravindranath * 258889a36810SAnil Ravindranath * Return value 258989a36810SAnil Ravindranath * none 259089a36810SAnil Ravindranath */ 259189a36810SAnil Ravindranath static void pmcraid_frame_auto_sense(struct pmcraid_cmd *cmd) 259289a36810SAnil Ravindranath { 259389a36810SAnil Ravindranath u8 *sense_buf = cmd->scsi_cmd->sense_buffer; 259489a36810SAnil Ravindranath struct pmcraid_resource_entry *res = cmd->scsi_cmd->device->hostdata; 259589a36810SAnil Ravindranath struct pmcraid_ioasa *ioasa = &cmd->ioa_cb->ioasa; 259689a36810SAnil Ravindranath u32 ioasc = le32_to_cpu(ioasa->ioasc); 259789a36810SAnil Ravindranath u32 failing_lba = 0; 259889a36810SAnil Ravindranath 259989a36810SAnil Ravindranath memset(sense_buf, 0, SCSI_SENSE_BUFFERSIZE); 260089a36810SAnil Ravindranath cmd->scsi_cmd->result = SAM_STAT_CHECK_CONDITION; 260189a36810SAnil Ravindranath 260289a36810SAnil Ravindranath if (RES_IS_VSET(res->cfg_entry) && 260389a36810SAnil Ravindranath ioasc == PMCRAID_IOASC_ME_READ_ERROR_NO_REALLOC && 260489a36810SAnil Ravindranath ioasa->u.vset.failing_lba_hi != 0) { 260589a36810SAnil Ravindranath 260689a36810SAnil Ravindranath sense_buf[0] = 0x72; 260789a36810SAnil Ravindranath sense_buf[1] = PMCRAID_IOASC_SENSE_KEY(ioasc); 260889a36810SAnil Ravindranath sense_buf[2] = PMCRAID_IOASC_SENSE_CODE(ioasc); 260989a36810SAnil Ravindranath sense_buf[3] = PMCRAID_IOASC_SENSE_QUAL(ioasc); 261089a36810SAnil Ravindranath 261189a36810SAnil Ravindranath sense_buf[7] = 12; 261289a36810SAnil Ravindranath sense_buf[8] = 0; 261389a36810SAnil Ravindranath sense_buf[9] = 0x0A; 261489a36810SAnil Ravindranath sense_buf[10] = 0x80; 261589a36810SAnil Ravindranath 261689a36810SAnil Ravindranath failing_lba = le32_to_cpu(ioasa->u.vset.failing_lba_hi); 261789a36810SAnil Ravindranath 261889a36810SAnil Ravindranath sense_buf[12] = (failing_lba & 0xff000000) >> 24; 261989a36810SAnil Ravindranath sense_buf[13] = (failing_lba & 0x00ff0000) >> 16; 262089a36810SAnil Ravindranath sense_buf[14] = (failing_lba & 0x0000ff00) >> 8; 262189a36810SAnil Ravindranath sense_buf[15] = failing_lba & 0x000000ff; 262289a36810SAnil Ravindranath 262389a36810SAnil Ravindranath failing_lba = le32_to_cpu(ioasa->u.vset.failing_lba_lo); 262489a36810SAnil Ravindranath 262589a36810SAnil Ravindranath sense_buf[16] = (failing_lba & 0xff000000) >> 24; 262689a36810SAnil Ravindranath sense_buf[17] = (failing_lba & 0x00ff0000) >> 16; 262789a36810SAnil Ravindranath sense_buf[18] = (failing_lba & 0x0000ff00) >> 8; 262889a36810SAnil Ravindranath sense_buf[19] = failing_lba & 0x000000ff; 262989a36810SAnil Ravindranath } else { 263089a36810SAnil Ravindranath sense_buf[0] = 0x70; 263189a36810SAnil Ravindranath sense_buf[2] = PMCRAID_IOASC_SENSE_KEY(ioasc); 263289a36810SAnil Ravindranath sense_buf[12] = PMCRAID_IOASC_SENSE_CODE(ioasc); 263389a36810SAnil Ravindranath sense_buf[13] = PMCRAID_IOASC_SENSE_QUAL(ioasc); 263489a36810SAnil Ravindranath 263589a36810SAnil Ravindranath if (ioasc == PMCRAID_IOASC_ME_READ_ERROR_NO_REALLOC) { 263689a36810SAnil Ravindranath if (RES_IS_VSET(res->cfg_entry)) 263789a36810SAnil Ravindranath failing_lba = 263889a36810SAnil Ravindranath le32_to_cpu(ioasa->u. 263989a36810SAnil Ravindranath vset.failing_lba_lo); 264089a36810SAnil Ravindranath sense_buf[0] |= 0x80; 264189a36810SAnil Ravindranath sense_buf[3] = (failing_lba >> 24) & 0xff; 264289a36810SAnil Ravindranath sense_buf[4] = (failing_lba >> 16) & 0xff; 264389a36810SAnil Ravindranath sense_buf[5] = (failing_lba >> 8) & 0xff; 264489a36810SAnil Ravindranath sense_buf[6] = failing_lba & 0xff; 264589a36810SAnil Ravindranath } 264689a36810SAnil Ravindranath 264789a36810SAnil Ravindranath sense_buf[7] = 6; /* additional length */ 264889a36810SAnil Ravindranath } 264989a36810SAnil Ravindranath } 265089a36810SAnil Ravindranath 265189a36810SAnil Ravindranath /** 265289a36810SAnil Ravindranath * pmcraid_error_handler - Error response handlers for a SCSI op 265389a36810SAnil Ravindranath * @cmd: pointer to pmcraid_cmd that has failed 265489a36810SAnil Ravindranath * 265589a36810SAnil Ravindranath * This function determines whether or not to initiate ERP on the affected 265689a36810SAnil Ravindranath * device. This is called from a tasklet, which doesn't hold any locks. 265789a36810SAnil Ravindranath * 265889a36810SAnil Ravindranath * Return value: 265989a36810SAnil Ravindranath * 0 it caller can complete the request, otherwise 1 where in error 266089a36810SAnil Ravindranath * handler itself completes the request and returns the command block 266189a36810SAnil Ravindranath * back to free-pool 266289a36810SAnil Ravindranath */ 266389a36810SAnil Ravindranath static int pmcraid_error_handler(struct pmcraid_cmd *cmd) 266489a36810SAnil Ravindranath { 266589a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; 266689a36810SAnil Ravindranath struct pmcraid_resource_entry *res = scsi_cmd->device->hostdata; 266789a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 266889a36810SAnil Ravindranath struct pmcraid_ioasa *ioasa = &cmd->ioa_cb->ioasa; 266989a36810SAnil Ravindranath u32 ioasc = le32_to_cpu(ioasa->ioasc); 267089a36810SAnil Ravindranath u32 masked_ioasc = ioasc & PMCRAID_IOASC_SENSE_MASK; 267189a36810SAnil Ravindranath u32 sense_copied = 0; 267289a36810SAnil Ravindranath 267389a36810SAnil Ravindranath if (!res) { 267489a36810SAnil Ravindranath pmcraid_info("resource pointer is NULL\n"); 267589a36810SAnil Ravindranath return 0; 267689a36810SAnil Ravindranath } 267789a36810SAnil Ravindranath 267889a36810SAnil Ravindranath /* If this was a SCSI read/write command keep count of errors */ 267989a36810SAnil Ravindranath if (SCSI_CMD_TYPE(scsi_cmd->cmnd[0]) == SCSI_READ_CMD) 268089a36810SAnil Ravindranath atomic_inc(&res->read_failures); 268189a36810SAnil Ravindranath else if (SCSI_CMD_TYPE(scsi_cmd->cmnd[0]) == SCSI_WRITE_CMD) 268289a36810SAnil Ravindranath atomic_inc(&res->write_failures); 268389a36810SAnil Ravindranath 268489a36810SAnil Ravindranath if (!RES_IS_GSCSI(res->cfg_entry) && 268589a36810SAnil Ravindranath masked_ioasc != PMCRAID_IOASC_HW_DEVICE_BUS_STATUS_ERROR) { 268689a36810SAnil Ravindranath pmcraid_frame_auto_sense(cmd); 268789a36810SAnil Ravindranath } 268889a36810SAnil Ravindranath 268989a36810SAnil Ravindranath /* Log IOASC/IOASA information based on user settings */ 269089a36810SAnil Ravindranath pmcraid_ioasc_logger(ioasc, cmd); 269189a36810SAnil Ravindranath 269289a36810SAnil Ravindranath switch (masked_ioasc) { 269389a36810SAnil Ravindranath 269489a36810SAnil Ravindranath case PMCRAID_IOASC_AC_TERMINATED_BY_HOST: 269589a36810SAnil Ravindranath scsi_cmd->result |= (DID_ABORT << 16); 269689a36810SAnil Ravindranath break; 269789a36810SAnil Ravindranath 269889a36810SAnil Ravindranath case PMCRAID_IOASC_IR_INVALID_RESOURCE_HANDLE: 269989a36810SAnil Ravindranath case PMCRAID_IOASC_HW_CANNOT_COMMUNICATE: 270089a36810SAnil Ravindranath scsi_cmd->result |= (DID_NO_CONNECT << 16); 270189a36810SAnil Ravindranath break; 270289a36810SAnil Ravindranath 270389a36810SAnil Ravindranath case PMCRAID_IOASC_NR_SYNC_REQUIRED: 270489a36810SAnil Ravindranath res->sync_reqd = 1; 270589a36810SAnil Ravindranath scsi_cmd->result |= (DID_IMM_RETRY << 16); 270689a36810SAnil Ravindranath break; 270789a36810SAnil Ravindranath 270889a36810SAnil Ravindranath case PMCRAID_IOASC_ME_READ_ERROR_NO_REALLOC: 270989a36810SAnil Ravindranath scsi_cmd->result |= (DID_PASSTHROUGH << 16); 271089a36810SAnil Ravindranath break; 271189a36810SAnil Ravindranath 271289a36810SAnil Ravindranath case PMCRAID_IOASC_UA_BUS_WAS_RESET: 271389a36810SAnil Ravindranath case PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER: 271489a36810SAnil Ravindranath if (!res->reset_progress) 271589a36810SAnil Ravindranath scsi_report_bus_reset(pinstance->host, 271689a36810SAnil Ravindranath scsi_cmd->device->channel); 271789a36810SAnil Ravindranath scsi_cmd->result |= (DID_ERROR << 16); 271889a36810SAnil Ravindranath break; 271989a36810SAnil Ravindranath 272089a36810SAnil Ravindranath case PMCRAID_IOASC_HW_DEVICE_BUS_STATUS_ERROR: 272189a36810SAnil Ravindranath scsi_cmd->result |= PMCRAID_IOASC_SENSE_STATUS(ioasc); 272289a36810SAnil Ravindranath res->sync_reqd = 1; 272389a36810SAnil Ravindranath 272489a36810SAnil Ravindranath /* if check_condition is not active return with error otherwise 272589a36810SAnil Ravindranath * get/frame the sense buffer 272689a36810SAnil Ravindranath */ 272789a36810SAnil Ravindranath if (PMCRAID_IOASC_SENSE_STATUS(ioasc) != 272889a36810SAnil Ravindranath SAM_STAT_CHECK_CONDITION && 272989a36810SAnil Ravindranath PMCRAID_IOASC_SENSE_STATUS(ioasc) != SAM_STAT_ACA_ACTIVE) 273089a36810SAnil Ravindranath return 0; 273189a36810SAnil Ravindranath 273289a36810SAnil Ravindranath /* If we have auto sense data as part of IOASA pass it to 273389a36810SAnil Ravindranath * mid-layer 273489a36810SAnil Ravindranath */ 273589a36810SAnil Ravindranath if (ioasa->auto_sense_length != 0) { 273689a36810SAnil Ravindranath short sense_len = ioasa->auto_sense_length; 273789a36810SAnil Ravindranath int data_size = min_t(u16, le16_to_cpu(sense_len), 273889a36810SAnil Ravindranath SCSI_SENSE_BUFFERSIZE); 273989a36810SAnil Ravindranath 274089a36810SAnil Ravindranath memcpy(scsi_cmd->sense_buffer, 274189a36810SAnil Ravindranath ioasa->sense_data, 274289a36810SAnil Ravindranath data_size); 274389a36810SAnil Ravindranath sense_copied = 1; 274489a36810SAnil Ravindranath } 274589a36810SAnil Ravindranath 2746a70757baSAnil Ravindranath if (RES_IS_GSCSI(res->cfg_entry)) 274789a36810SAnil Ravindranath pmcraid_cancel_all(cmd, sense_copied); 2748a70757baSAnil Ravindranath else if (sense_copied) 274989a36810SAnil Ravindranath pmcraid_erp_done(cmd); 2750a70757baSAnil Ravindranath else 275189a36810SAnil Ravindranath pmcraid_request_sense(cmd); 275289a36810SAnil Ravindranath 275389a36810SAnil Ravindranath return 1; 275489a36810SAnil Ravindranath 275589a36810SAnil Ravindranath case PMCRAID_IOASC_NR_INIT_CMD_REQUIRED: 275689a36810SAnil Ravindranath break; 275789a36810SAnil Ravindranath 275889a36810SAnil Ravindranath default: 275989a36810SAnil Ravindranath if (PMCRAID_IOASC_SENSE_KEY(ioasc) > RECOVERED_ERROR) 276089a36810SAnil Ravindranath scsi_cmd->result |= (DID_ERROR << 16); 276189a36810SAnil Ravindranath break; 276289a36810SAnil Ravindranath } 276389a36810SAnil Ravindranath return 0; 276489a36810SAnil Ravindranath } 276589a36810SAnil Ravindranath 276689a36810SAnil Ravindranath /** 276789a36810SAnil Ravindranath * pmcraid_reset_device - device reset handler functions 276889a36810SAnil Ravindranath * 276989a36810SAnil Ravindranath * @scsi_cmd: scsi command struct 277089a36810SAnil Ravindranath * @modifier: reset modifier indicating the reset sequence to be performed 277189a36810SAnil Ravindranath * 277289a36810SAnil Ravindranath * This function issues a device reset to the affected device. 277389a36810SAnil Ravindranath * A LUN reset will be sent to the device first. If that does 277489a36810SAnil Ravindranath * not work, a target reset will be sent. 277589a36810SAnil Ravindranath * 277689a36810SAnil Ravindranath * Return value: 277789a36810SAnil Ravindranath * SUCCESS / FAILED 277889a36810SAnil Ravindranath */ 277989a36810SAnil Ravindranath static int pmcraid_reset_device( 278089a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd, 278189a36810SAnil Ravindranath unsigned long timeout, 278289a36810SAnil Ravindranath u8 modifier 278389a36810SAnil Ravindranath ) 278489a36810SAnil Ravindranath { 278589a36810SAnil Ravindranath struct pmcraid_cmd *cmd; 278689a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 278789a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 278889a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb; 278989a36810SAnil Ravindranath unsigned long lock_flags; 279089a36810SAnil Ravindranath u32 ioasc; 279189a36810SAnil Ravindranath 279289a36810SAnil Ravindranath pinstance = 279389a36810SAnil Ravindranath (struct pmcraid_instance *)scsi_cmd->device->host->hostdata; 279489a36810SAnil Ravindranath res = scsi_cmd->device->hostdata; 279589a36810SAnil Ravindranath 279689a36810SAnil Ravindranath if (!res) { 279734876402SAnil Ravindranath sdev_printk(KERN_ERR, scsi_cmd->device, 279834876402SAnil Ravindranath "reset_device: NULL resource pointer\n"); 279989a36810SAnil Ravindranath return FAILED; 280089a36810SAnil Ravindranath } 280189a36810SAnil Ravindranath 280289a36810SAnil Ravindranath /* If adapter is currently going through reset/reload, return failed. 280389a36810SAnil Ravindranath * This will force the mid-layer to call _eh_bus/host reset, which 280489a36810SAnil Ravindranath * will then go to sleep and wait for the reset to complete 280589a36810SAnil Ravindranath */ 280689a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 280789a36810SAnil Ravindranath if (pinstance->ioa_reset_in_progress || 280889a36810SAnil Ravindranath pinstance->ioa_state == IOA_STATE_DEAD) { 280989a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 281089a36810SAnil Ravindranath return FAILED; 281189a36810SAnil Ravindranath } 281289a36810SAnil Ravindranath 281389a36810SAnil Ravindranath res->reset_progress = 1; 281489a36810SAnil Ravindranath pmcraid_info("Resetting %s resource with addr %x\n", 281589a36810SAnil Ravindranath ((modifier & RESET_DEVICE_LUN) ? "LUN" : 281689a36810SAnil Ravindranath ((modifier & RESET_DEVICE_TARGET) ? "TARGET" : "BUS")), 281789a36810SAnil Ravindranath le32_to_cpu(res->cfg_entry.resource_address)); 281889a36810SAnil Ravindranath 281989a36810SAnil Ravindranath /* get a free cmd block */ 282089a36810SAnil Ravindranath cmd = pmcraid_get_free_cmd(pinstance); 282189a36810SAnil Ravindranath 282289a36810SAnil Ravindranath if (cmd == NULL) { 282389a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 282489a36810SAnil Ravindranath pmcraid_err("%s: no cmd blocks are available\n", __func__); 282589a36810SAnil Ravindranath return FAILED; 282689a36810SAnil Ravindranath } 282789a36810SAnil Ravindranath 282889a36810SAnil Ravindranath ioarcb = &cmd->ioa_cb->ioarcb; 282989a36810SAnil Ravindranath ioarcb->resource_handle = res->cfg_entry.resource_handle; 283089a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_IOACMD; 283189a36810SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_RESET_DEVICE; 283289a36810SAnil Ravindranath 283389a36810SAnil Ravindranath /* Initialize reset modifier bits */ 283489a36810SAnil Ravindranath if (modifier) 283589a36810SAnil Ravindranath modifier = ENABLE_RESET_MODIFIER | modifier; 283689a36810SAnil Ravindranath 283789a36810SAnil Ravindranath ioarcb->cdb[1] = modifier; 283889a36810SAnil Ravindranath 283989a36810SAnil Ravindranath init_completion(&cmd->wait_for_completion); 284089a36810SAnil Ravindranath cmd->completion_req = 1; 284189a36810SAnil Ravindranath 284289a36810SAnil Ravindranath pmcraid_info("cmd(CDB[0] = %x) for %x with index = %d\n", 284389a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 284489a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioarcb.resource_handle), 284589a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle) >> 2); 284689a36810SAnil Ravindranath 284789a36810SAnil Ravindranath pmcraid_send_cmd(cmd, 284889a36810SAnil Ravindranath pmcraid_internal_done, 284989a36810SAnil Ravindranath timeout, 285089a36810SAnil Ravindranath pmcraid_timeout_handler); 285189a36810SAnil Ravindranath 285289a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 285389a36810SAnil Ravindranath 285489a36810SAnil Ravindranath /* RESET_DEVICE command completes after all pending IOARCBs are 285589a36810SAnil Ravindranath * completed. Once this command is completed, pmcraind_internal_done 285689a36810SAnil Ravindranath * will wake up the 'completion' queue. 285789a36810SAnil Ravindranath */ 285889a36810SAnil Ravindranath wait_for_completion(&cmd->wait_for_completion); 285989a36810SAnil Ravindranath 286089a36810SAnil Ravindranath /* complete the command here itself and return the command block 286189a36810SAnil Ravindranath * to free list 286289a36810SAnil Ravindranath */ 286389a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 286489a36810SAnil Ravindranath res->reset_progress = 0; 286589a36810SAnil Ravindranath ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); 286689a36810SAnil Ravindranath 286789a36810SAnil Ravindranath /* set the return value based on the returned ioasc */ 286889a36810SAnil Ravindranath return PMCRAID_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS; 286989a36810SAnil Ravindranath } 287089a36810SAnil Ravindranath 287189a36810SAnil Ravindranath /** 287289a36810SAnil Ravindranath * _pmcraid_io_done - helper for pmcraid_io_done function 287389a36810SAnil Ravindranath * 287489a36810SAnil Ravindranath * @cmd: pointer to pmcraid command struct 287589a36810SAnil Ravindranath * @reslen: residual data length to be set in the ioasa 287689a36810SAnil Ravindranath * @ioasc: ioasc either returned by IOA or set by driver itself. 287789a36810SAnil Ravindranath * 287889a36810SAnil Ravindranath * This function is invoked by pmcraid_io_done to complete mid-layer 287989a36810SAnil Ravindranath * scsi ops. 288089a36810SAnil Ravindranath * 288189a36810SAnil Ravindranath * Return value: 288289a36810SAnil Ravindranath * 0 if caller is required to return it to free_pool. Returns 1 if 288389a36810SAnil Ravindranath * caller need not worry about freeing command block as error handler 288489a36810SAnil Ravindranath * will take care of that. 288589a36810SAnil Ravindranath */ 288689a36810SAnil Ravindranath 288789a36810SAnil Ravindranath static int _pmcraid_io_done(struct pmcraid_cmd *cmd, int reslen, int ioasc) 288889a36810SAnil Ravindranath { 288989a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; 289089a36810SAnil Ravindranath int rc = 0; 289189a36810SAnil Ravindranath 289289a36810SAnil Ravindranath scsi_set_resid(scsi_cmd, reslen); 289389a36810SAnil Ravindranath 289489a36810SAnil Ravindranath pmcraid_info("response(%d) CDB[0] = %x ioasc:result: %x:%x\n", 289589a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle) >> 2, 289689a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 289789a36810SAnil Ravindranath ioasc, scsi_cmd->result); 289889a36810SAnil Ravindranath 289989a36810SAnil Ravindranath if (PMCRAID_IOASC_SENSE_KEY(ioasc) != 0) 290089a36810SAnil Ravindranath rc = pmcraid_error_handler(cmd); 290189a36810SAnil Ravindranath 290289a36810SAnil Ravindranath if (rc == 0) { 290389a36810SAnil Ravindranath scsi_dma_unmap(scsi_cmd); 290489a36810SAnil Ravindranath scsi_cmd->scsi_done(scsi_cmd); 290589a36810SAnil Ravindranath } 290689a36810SAnil Ravindranath 290789a36810SAnil Ravindranath return rc; 290889a36810SAnil Ravindranath } 290989a36810SAnil Ravindranath 291089a36810SAnil Ravindranath /** 291189a36810SAnil Ravindranath * pmcraid_io_done - SCSI completion function 291289a36810SAnil Ravindranath * 291389a36810SAnil Ravindranath * @cmd: pointer to pmcraid command struct 291489a36810SAnil Ravindranath * 291589a36810SAnil Ravindranath * This function is invoked by tasklet/mid-layer error handler to completing 291689a36810SAnil Ravindranath * the SCSI ops sent from mid-layer. 291789a36810SAnil Ravindranath * 291889a36810SAnil Ravindranath * Return value 291989a36810SAnil Ravindranath * none 292089a36810SAnil Ravindranath */ 292189a36810SAnil Ravindranath 292289a36810SAnil Ravindranath static void pmcraid_io_done(struct pmcraid_cmd *cmd) 292389a36810SAnil Ravindranath { 292489a36810SAnil Ravindranath u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); 292589a36810SAnil Ravindranath u32 reslen = le32_to_cpu(cmd->ioa_cb->ioasa.residual_data_length); 292689a36810SAnil Ravindranath 292789a36810SAnil Ravindranath if (_pmcraid_io_done(cmd, reslen, ioasc) == 0) 292889a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 292989a36810SAnil Ravindranath } 293089a36810SAnil Ravindranath 293189a36810SAnil Ravindranath /** 293289a36810SAnil Ravindranath * pmcraid_abort_cmd - Aborts a single IOARCB already submitted to IOA 293389a36810SAnil Ravindranath * 293489a36810SAnil Ravindranath * @cmd: command block of the command to be aborted 293589a36810SAnil Ravindranath * 293689a36810SAnil Ravindranath * Return Value: 293789a36810SAnil Ravindranath * returns pointer to command structure used as cancelling cmd 293889a36810SAnil Ravindranath */ 293989a36810SAnil Ravindranath static struct pmcraid_cmd *pmcraid_abort_cmd(struct pmcraid_cmd *cmd) 294089a36810SAnil Ravindranath { 294189a36810SAnil Ravindranath struct pmcraid_cmd *cancel_cmd; 294289a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 294389a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 294489a36810SAnil Ravindranath 294589a36810SAnil Ravindranath pinstance = (struct pmcraid_instance *)cmd->drv_inst; 294689a36810SAnil Ravindranath res = cmd->scsi_cmd->device->hostdata; 294789a36810SAnil Ravindranath 294889a36810SAnil Ravindranath cancel_cmd = pmcraid_get_free_cmd(pinstance); 294989a36810SAnil Ravindranath 295089a36810SAnil Ravindranath if (cancel_cmd == NULL) { 295189a36810SAnil Ravindranath pmcraid_err("%s: no cmd blocks are available\n", __func__); 295289a36810SAnil Ravindranath return NULL; 295389a36810SAnil Ravindranath } 295489a36810SAnil Ravindranath 295589a36810SAnil Ravindranath pmcraid_prepare_cancel_cmd(cancel_cmd, cmd); 295689a36810SAnil Ravindranath 295789a36810SAnil Ravindranath pmcraid_info("aborting command CDB[0]= %x with index = %d\n", 295889a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 295989a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.response_handle >> 2); 296089a36810SAnil Ravindranath 296189a36810SAnil Ravindranath init_completion(&cancel_cmd->wait_for_completion); 296289a36810SAnil Ravindranath cancel_cmd->completion_req = 1; 296389a36810SAnil Ravindranath 296489a36810SAnil Ravindranath pmcraid_info("command (%d) CDB[0] = %x for %x\n", 296589a36810SAnil Ravindranath le32_to_cpu(cancel_cmd->ioa_cb->ioarcb.response_handle) >> 2, 2966c20c4267SAnil Ravindranath cancel_cmd->ioa_cb->ioarcb.cdb[0], 296789a36810SAnil Ravindranath le32_to_cpu(cancel_cmd->ioa_cb->ioarcb.resource_handle)); 296889a36810SAnil Ravindranath 296989a36810SAnil Ravindranath pmcraid_send_cmd(cancel_cmd, 297089a36810SAnil Ravindranath pmcraid_internal_done, 297189a36810SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, 297289a36810SAnil Ravindranath pmcraid_timeout_handler); 297389a36810SAnil Ravindranath return cancel_cmd; 297489a36810SAnil Ravindranath } 297589a36810SAnil Ravindranath 297689a36810SAnil Ravindranath /** 297789a36810SAnil Ravindranath * pmcraid_abort_complete - Waits for ABORT TASK completion 297889a36810SAnil Ravindranath * 297989a36810SAnil Ravindranath * @cancel_cmd: command block use as cancelling command 298089a36810SAnil Ravindranath * 298189a36810SAnil Ravindranath * Return Value: 298289a36810SAnil Ravindranath * returns SUCCESS if ABORT TASK has good completion 298389a36810SAnil Ravindranath * otherwise FAILED 298489a36810SAnil Ravindranath */ 298589a36810SAnil Ravindranath static int pmcraid_abort_complete(struct pmcraid_cmd *cancel_cmd) 298689a36810SAnil Ravindranath { 298789a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 298889a36810SAnil Ravindranath u32 ioasc; 298989a36810SAnil Ravindranath 299089a36810SAnil Ravindranath wait_for_completion(&cancel_cmd->wait_for_completion); 2991c20c4267SAnil Ravindranath res = cancel_cmd->res; 2992c20c4267SAnil Ravindranath cancel_cmd->res = NULL; 299389a36810SAnil Ravindranath ioasc = le32_to_cpu(cancel_cmd->ioa_cb->ioasa.ioasc); 299489a36810SAnil Ravindranath 299589a36810SAnil Ravindranath /* If the abort task is not timed out we will get a Good completion 299689a36810SAnil Ravindranath * as sense_key, otherwise we may get one the following responses 299725985edcSLucas De Marchi * due to subsequent bus reset or device reset. In case IOASC is 299889a36810SAnil Ravindranath * NR_SYNC_REQUIRED, set sync_reqd flag for the corresponding resource 299989a36810SAnil Ravindranath */ 300089a36810SAnil Ravindranath if (ioasc == PMCRAID_IOASC_UA_BUS_WAS_RESET || 300189a36810SAnil Ravindranath ioasc == PMCRAID_IOASC_NR_SYNC_REQUIRED) { 300289a36810SAnil Ravindranath if (ioasc == PMCRAID_IOASC_NR_SYNC_REQUIRED) 300389a36810SAnil Ravindranath res->sync_reqd = 1; 300489a36810SAnil Ravindranath ioasc = 0; 300589a36810SAnil Ravindranath } 300689a36810SAnil Ravindranath 300789a36810SAnil Ravindranath /* complete the command here itself */ 300889a36810SAnil Ravindranath pmcraid_return_cmd(cancel_cmd); 300989a36810SAnil Ravindranath return PMCRAID_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS; 301089a36810SAnil Ravindranath } 301189a36810SAnil Ravindranath 301289a36810SAnil Ravindranath /** 301389a36810SAnil Ravindranath * pmcraid_eh_abort_handler - entry point for aborting a single task on errors 301489a36810SAnil Ravindranath * 301589a36810SAnil Ravindranath * @scsi_cmd: scsi command struct given by mid-layer. When this is called 301689a36810SAnil Ravindranath * mid-layer ensures that no other commands are queued. This 301789a36810SAnil Ravindranath * never gets called under interrupt, but a separate eh thread. 301889a36810SAnil Ravindranath * 301989a36810SAnil Ravindranath * Return value: 302089a36810SAnil Ravindranath * SUCCESS / FAILED 302189a36810SAnil Ravindranath */ 302289a36810SAnil Ravindranath static int pmcraid_eh_abort_handler(struct scsi_cmnd *scsi_cmd) 302389a36810SAnil Ravindranath { 302489a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 302589a36810SAnil Ravindranath struct pmcraid_cmd *cmd; 302689a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 302789a36810SAnil Ravindranath unsigned long host_lock_flags; 302889a36810SAnil Ravindranath unsigned long pending_lock_flags; 302989a36810SAnil Ravindranath struct pmcraid_cmd *cancel_cmd = NULL; 303089a36810SAnil Ravindranath int cmd_found = 0; 303189a36810SAnil Ravindranath int rc = FAILED; 303289a36810SAnil Ravindranath 303389a36810SAnil Ravindranath pinstance = 303489a36810SAnil Ravindranath (struct pmcraid_instance *)scsi_cmd->device->host->hostdata; 303589a36810SAnil Ravindranath 303634876402SAnil Ravindranath scmd_printk(KERN_INFO, scsi_cmd, 303789a36810SAnil Ravindranath "I/O command timed out, aborting it.\n"); 303889a36810SAnil Ravindranath 303989a36810SAnil Ravindranath res = scsi_cmd->device->hostdata; 304089a36810SAnil Ravindranath 304189a36810SAnil Ravindranath if (res == NULL) 304289a36810SAnil Ravindranath return rc; 304389a36810SAnil Ravindranath 304489a36810SAnil Ravindranath /* If we are currently going through reset/reload, return failed. 304589a36810SAnil Ravindranath * This will force the mid-layer to eventually call 304689a36810SAnil Ravindranath * pmcraid_eh_host_reset which will then go to sleep and wait for the 304789a36810SAnil Ravindranath * reset to complete 304889a36810SAnil Ravindranath */ 304989a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, host_lock_flags); 305089a36810SAnil Ravindranath 305189a36810SAnil Ravindranath if (pinstance->ioa_reset_in_progress || 305289a36810SAnil Ravindranath pinstance->ioa_state == IOA_STATE_DEAD) { 305389a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 305489a36810SAnil Ravindranath host_lock_flags); 305589a36810SAnil Ravindranath return rc; 305689a36810SAnil Ravindranath } 305789a36810SAnil Ravindranath 305889a36810SAnil Ravindranath /* loop over pending cmd list to find cmd corresponding to this 305989a36810SAnil Ravindranath * scsi_cmd. Note that this command might not have been completed 306089a36810SAnil Ravindranath * already. locking: all pending commands are protected with 306189a36810SAnil Ravindranath * pending_pool_lock. 306289a36810SAnil Ravindranath */ 306389a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->pending_pool_lock, pending_lock_flags); 306489a36810SAnil Ravindranath list_for_each_entry(cmd, &pinstance->pending_cmd_pool, free_list) { 306589a36810SAnil Ravindranath 306689a36810SAnil Ravindranath if (cmd->scsi_cmd == scsi_cmd) { 306789a36810SAnil Ravindranath cmd_found = 1; 306889a36810SAnil Ravindranath break; 306989a36810SAnil Ravindranath } 307089a36810SAnil Ravindranath } 307189a36810SAnil Ravindranath 307289a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->pending_pool_lock, 307389a36810SAnil Ravindranath pending_lock_flags); 307489a36810SAnil Ravindranath 307589a36810SAnil Ravindranath /* If the command to be aborted was given to IOA and still pending with 307689a36810SAnil Ravindranath * it, send ABORT_TASK to abort this and wait for its completion 307789a36810SAnil Ravindranath */ 307889a36810SAnil Ravindranath if (cmd_found) 307989a36810SAnil Ravindranath cancel_cmd = pmcraid_abort_cmd(cmd); 308089a36810SAnil Ravindranath 308189a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 308289a36810SAnil Ravindranath host_lock_flags); 308389a36810SAnil Ravindranath 308489a36810SAnil Ravindranath if (cancel_cmd) { 3085c20c4267SAnil Ravindranath cancel_cmd->res = cmd->scsi_cmd->device->hostdata; 308689a36810SAnil Ravindranath rc = pmcraid_abort_complete(cancel_cmd); 308789a36810SAnil Ravindranath } 308889a36810SAnil Ravindranath 308989a36810SAnil Ravindranath return cmd_found ? rc : SUCCESS; 309089a36810SAnil Ravindranath } 309189a36810SAnil Ravindranath 309289a36810SAnil Ravindranath /** 309389a36810SAnil Ravindranath * pmcraid_eh_xxxx_reset_handler - bus/target/device reset handler callbacks 309489a36810SAnil Ravindranath * 309589a36810SAnil Ravindranath * @scmd: pointer to scsi_cmd that was sent to the resource to be reset. 309689a36810SAnil Ravindranath * 309789a36810SAnil Ravindranath * All these routines invokve pmcraid_reset_device with appropriate parameters. 309889a36810SAnil Ravindranath * Since these are called from mid-layer EH thread, no other IO will be queued 309989a36810SAnil Ravindranath * to the resource being reset. However, control path (IOCTL) may be active so 310089a36810SAnil Ravindranath * it is necessary to synchronize IOARRIN writes which pmcraid_reset_device 310189a36810SAnil Ravindranath * takes care by locking/unlocking host_lock. 310289a36810SAnil Ravindranath * 310389a36810SAnil Ravindranath * Return value 310489a36810SAnil Ravindranath * SUCCESS or FAILED 310589a36810SAnil Ravindranath */ 310689a36810SAnil Ravindranath static int pmcraid_eh_device_reset_handler(struct scsi_cmnd *scmd) 310789a36810SAnil Ravindranath { 310834876402SAnil Ravindranath scmd_printk(KERN_INFO, scmd, 310934876402SAnil Ravindranath "resetting device due to an I/O command timeout.\n"); 311089a36810SAnil Ravindranath return pmcraid_reset_device(scmd, 311189a36810SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, 311289a36810SAnil Ravindranath RESET_DEVICE_LUN); 311389a36810SAnil Ravindranath } 311489a36810SAnil Ravindranath 311589a36810SAnil Ravindranath static int pmcraid_eh_bus_reset_handler(struct scsi_cmnd *scmd) 311689a36810SAnil Ravindranath { 311734876402SAnil Ravindranath scmd_printk(KERN_INFO, scmd, 311834876402SAnil Ravindranath "Doing bus reset due to an I/O command timeout.\n"); 311989a36810SAnil Ravindranath return pmcraid_reset_device(scmd, 312089a36810SAnil Ravindranath PMCRAID_RESET_BUS_TIMEOUT, 312189a36810SAnil Ravindranath RESET_DEVICE_BUS); 312289a36810SAnil Ravindranath } 312389a36810SAnil Ravindranath 312489a36810SAnil Ravindranath static int pmcraid_eh_target_reset_handler(struct scsi_cmnd *scmd) 312589a36810SAnil Ravindranath { 312634876402SAnil Ravindranath scmd_printk(KERN_INFO, scmd, 312734876402SAnil Ravindranath "Doing target reset due to an I/O command timeout.\n"); 312889a36810SAnil Ravindranath return pmcraid_reset_device(scmd, 312989a36810SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, 313089a36810SAnil Ravindranath RESET_DEVICE_TARGET); 313189a36810SAnil Ravindranath } 313289a36810SAnil Ravindranath 313389a36810SAnil Ravindranath /** 313489a36810SAnil Ravindranath * pmcraid_eh_host_reset_handler - adapter reset handler callback 313589a36810SAnil Ravindranath * 313689a36810SAnil Ravindranath * @scmd: pointer to scsi_cmd that was sent to a resource of adapter 313789a36810SAnil Ravindranath * 313889a36810SAnil Ravindranath * Initiates adapter reset to bring it up to operational state 313989a36810SAnil Ravindranath * 314089a36810SAnil Ravindranath * Return value 314189a36810SAnil Ravindranath * SUCCESS or FAILED 314289a36810SAnil Ravindranath */ 314389a36810SAnil Ravindranath static int pmcraid_eh_host_reset_handler(struct scsi_cmnd *scmd) 314489a36810SAnil Ravindranath { 314589a36810SAnil Ravindranath unsigned long interval = 10000; /* 10 seconds interval */ 314689a36810SAnil Ravindranath int waits = jiffies_to_msecs(PMCRAID_RESET_HOST_TIMEOUT) / interval; 314789a36810SAnil Ravindranath struct pmcraid_instance *pinstance = 314889a36810SAnil Ravindranath (struct pmcraid_instance *)(scmd->device->host->hostdata); 314989a36810SAnil Ravindranath 315089a36810SAnil Ravindranath 315189a36810SAnil Ravindranath /* wait for an additional 150 seconds just in case firmware could come 315289a36810SAnil Ravindranath * up and if it could complete all the pending commands excluding the 315389a36810SAnil Ravindranath * two HCAM (CCN and LDN). 315489a36810SAnil Ravindranath */ 315589a36810SAnil Ravindranath while (waits--) { 315689a36810SAnil Ravindranath if (atomic_read(&pinstance->outstanding_cmds) <= 315789a36810SAnil Ravindranath PMCRAID_MAX_HCAM_CMD) 315889a36810SAnil Ravindranath return SUCCESS; 315989a36810SAnil Ravindranath msleep(interval); 316089a36810SAnil Ravindranath } 316189a36810SAnil Ravindranath 316289a36810SAnil Ravindranath dev_err(&pinstance->pdev->dev, 316389a36810SAnil Ravindranath "Adapter being reset due to an I/O command timeout.\n"); 316489a36810SAnil Ravindranath return pmcraid_reset_bringup(pinstance) == 0 ? SUCCESS : FAILED; 316589a36810SAnil Ravindranath } 316689a36810SAnil Ravindranath 316789a36810SAnil Ravindranath /** 316889a36810SAnil Ravindranath * pmcraid_task_attributes - Translate SPI Q-Tags to task attributes 316989a36810SAnil Ravindranath * @scsi_cmd: scsi command struct 317089a36810SAnil Ravindranath * 317189a36810SAnil Ravindranath * Return value 317289a36810SAnil Ravindranath * number of tags or 0 if the task is not tagged 317389a36810SAnil Ravindranath */ 317489a36810SAnil Ravindranath static u8 pmcraid_task_attributes(struct scsi_cmnd *scsi_cmd) 317589a36810SAnil Ravindranath { 317689a36810SAnil Ravindranath char tag[2]; 317789a36810SAnil Ravindranath u8 rc = 0; 317889a36810SAnil Ravindranath 317989a36810SAnil Ravindranath if (scsi_populate_tag_msg(scsi_cmd, tag)) { 318089a36810SAnil Ravindranath switch (tag[0]) { 318189a36810SAnil Ravindranath case MSG_SIMPLE_TAG: 318289a36810SAnil Ravindranath rc = TASK_TAG_SIMPLE; 318389a36810SAnil Ravindranath break; 318489a36810SAnil Ravindranath case MSG_HEAD_TAG: 318589a36810SAnil Ravindranath rc = TASK_TAG_QUEUE_HEAD; 318689a36810SAnil Ravindranath break; 318789a36810SAnil Ravindranath case MSG_ORDERED_TAG: 318889a36810SAnil Ravindranath rc = TASK_TAG_ORDERED; 318989a36810SAnil Ravindranath break; 319089a36810SAnil Ravindranath }; 319189a36810SAnil Ravindranath } 319289a36810SAnil Ravindranath 319389a36810SAnil Ravindranath return rc; 319489a36810SAnil Ravindranath } 319589a36810SAnil Ravindranath 319689a36810SAnil Ravindranath 319789a36810SAnil Ravindranath /** 319889a36810SAnil Ravindranath * pmcraid_init_ioadls - initializes IOADL related fields in IOARCB 319989a36810SAnil Ravindranath * @cmd: pmcraid command struct 320089a36810SAnil Ravindranath * @sgcount: count of scatter-gather elements 320189a36810SAnil Ravindranath * 320289a36810SAnil Ravindranath * Return value 320389a36810SAnil Ravindranath * returns pointer pmcraid_ioadl_desc, initialized to point to internal 320489a36810SAnil Ravindranath * or external IOADLs 320589a36810SAnil Ravindranath */ 320689a36810SAnil Ravindranath struct pmcraid_ioadl_desc * 320789a36810SAnil Ravindranath pmcraid_init_ioadls(struct pmcraid_cmd *cmd, int sgcount) 320889a36810SAnil Ravindranath { 320989a36810SAnil Ravindranath struct pmcraid_ioadl_desc *ioadl; 321089a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 321189a36810SAnil Ravindranath int ioadl_count = 0; 321289a36810SAnil Ravindranath 321389a36810SAnil Ravindranath if (ioarcb->add_cmd_param_length) 321489a36810SAnil Ravindranath ioadl_count = DIV_ROUND_UP(ioarcb->add_cmd_param_length, 16); 321589a36810SAnil Ravindranath ioarcb->ioadl_length = 321689a36810SAnil Ravindranath sizeof(struct pmcraid_ioadl_desc) * sgcount; 321789a36810SAnil Ravindranath 321889a36810SAnil Ravindranath if ((sgcount + ioadl_count) > (ARRAY_SIZE(ioarcb->add_data.u.ioadl))) { 321989a36810SAnil Ravindranath /* external ioadls start at offset 0x80 from control_block 322089a36810SAnil Ravindranath * structure, re-using 24 out of 27 ioadls part of IOARCB. 322189a36810SAnil Ravindranath * It is necessary to indicate to firmware that driver is 322289a36810SAnil Ravindranath * using ioadls to be treated as external to IOARCB. 322389a36810SAnil Ravindranath */ 322489a36810SAnil Ravindranath ioarcb->ioarcb_bus_addr &= ~(0x1FULL); 322589a36810SAnil Ravindranath ioarcb->ioadl_bus_addr = 322689a36810SAnil Ravindranath cpu_to_le64((cmd->ioa_cb_bus_addr) + 322789a36810SAnil Ravindranath offsetof(struct pmcraid_ioarcb, 322889a36810SAnil Ravindranath add_data.u.ioadl[3])); 322989a36810SAnil Ravindranath ioadl = &ioarcb->add_data.u.ioadl[3]; 323089a36810SAnil Ravindranath } else { 323189a36810SAnil Ravindranath ioarcb->ioadl_bus_addr = 323289a36810SAnil Ravindranath cpu_to_le64((cmd->ioa_cb_bus_addr) + 323389a36810SAnil Ravindranath offsetof(struct pmcraid_ioarcb, 323489a36810SAnil Ravindranath add_data.u.ioadl[ioadl_count])); 323589a36810SAnil Ravindranath 323689a36810SAnil Ravindranath ioadl = &ioarcb->add_data.u.ioadl[ioadl_count]; 323789a36810SAnil Ravindranath ioarcb->ioarcb_bus_addr |= 323889a36810SAnil Ravindranath DIV_ROUND_CLOSEST(sgcount + ioadl_count, 8); 323989a36810SAnil Ravindranath } 324089a36810SAnil Ravindranath 324189a36810SAnil Ravindranath return ioadl; 324289a36810SAnil Ravindranath } 324389a36810SAnil Ravindranath 324489a36810SAnil Ravindranath /** 324589a36810SAnil Ravindranath * pmcraid_build_ioadl - Build a scatter/gather list and map the buffer 324689a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 324789a36810SAnil Ravindranath * @cmd: pmcraid command struct 324889a36810SAnil Ravindranath * 324989a36810SAnil Ravindranath * This function is invoked by queuecommand entry point while sending a command 325089a36810SAnil Ravindranath * to firmware. This builds ioadl descriptors and sets up ioarcb fields. 325189a36810SAnil Ravindranath * 325289a36810SAnil Ravindranath * Return value: 325389a36810SAnil Ravindranath * 0 on success or -1 on failure 325489a36810SAnil Ravindranath */ 325589a36810SAnil Ravindranath static int pmcraid_build_ioadl( 325689a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 325789a36810SAnil Ravindranath struct pmcraid_cmd *cmd 325889a36810SAnil Ravindranath ) 325989a36810SAnil Ravindranath { 326089a36810SAnil Ravindranath int i, nseg; 326189a36810SAnil Ravindranath struct scatterlist *sglist; 326289a36810SAnil Ravindranath 326389a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; 326489a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &(cmd->ioa_cb->ioarcb); 326589a36810SAnil Ravindranath struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; 326689a36810SAnil Ravindranath 326789a36810SAnil Ravindranath u32 length = scsi_bufflen(scsi_cmd); 326889a36810SAnil Ravindranath 326989a36810SAnil Ravindranath if (!length) 327089a36810SAnil Ravindranath return 0; 327189a36810SAnil Ravindranath 327289a36810SAnil Ravindranath nseg = scsi_dma_map(scsi_cmd); 327389a36810SAnil Ravindranath 327489a36810SAnil Ravindranath if (nseg < 0) { 327534876402SAnil Ravindranath scmd_printk(KERN_ERR, scsi_cmd, "scsi_map_dma failed!\n"); 327689a36810SAnil Ravindranath return -1; 327789a36810SAnil Ravindranath } else if (nseg > PMCRAID_MAX_IOADLS) { 327889a36810SAnil Ravindranath scsi_dma_unmap(scsi_cmd); 327934876402SAnil Ravindranath scmd_printk(KERN_ERR, scsi_cmd, 328089a36810SAnil Ravindranath "sg count is (%d) more than allowed!\n", nseg); 328189a36810SAnil Ravindranath return -1; 328289a36810SAnil Ravindranath } 328389a36810SAnil Ravindranath 328489a36810SAnil Ravindranath /* Initialize IOARCB data transfer length fields */ 328589a36810SAnil Ravindranath if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) 328689a36810SAnil Ravindranath ioarcb->request_flags0 |= TRANSFER_DIR_WRITE; 328789a36810SAnil Ravindranath 328889a36810SAnil Ravindranath ioarcb->request_flags0 |= NO_LINK_DESCS; 328989a36810SAnil Ravindranath ioarcb->data_transfer_length = cpu_to_le32(length); 329089a36810SAnil Ravindranath ioadl = pmcraid_init_ioadls(cmd, nseg); 329189a36810SAnil Ravindranath 329289a36810SAnil Ravindranath /* Initialize IOADL descriptor addresses */ 329389a36810SAnil Ravindranath scsi_for_each_sg(scsi_cmd, sglist, nseg, i) { 329489a36810SAnil Ravindranath ioadl[i].data_len = cpu_to_le32(sg_dma_len(sglist)); 329589a36810SAnil Ravindranath ioadl[i].address = cpu_to_le64(sg_dma_address(sglist)); 329689a36810SAnil Ravindranath ioadl[i].flags = 0; 329789a36810SAnil Ravindranath } 329889a36810SAnil Ravindranath /* setup last descriptor */ 329988197966SAnil Ravindranath ioadl[i - 1].flags = IOADL_FLAGS_LAST_DESC; 330089a36810SAnil Ravindranath 330189a36810SAnil Ravindranath return 0; 330289a36810SAnil Ravindranath } 330389a36810SAnil Ravindranath 330489a36810SAnil Ravindranath /** 330589a36810SAnil Ravindranath * pmcraid_free_sglist - Frees an allocated SG buffer list 330689a36810SAnil Ravindranath * @sglist: scatter/gather list pointer 330789a36810SAnil Ravindranath * 330889a36810SAnil Ravindranath * Free a DMA'able memory previously allocated with pmcraid_alloc_sglist 330989a36810SAnil Ravindranath * 331089a36810SAnil Ravindranath * Return value: 331189a36810SAnil Ravindranath * none 331289a36810SAnil Ravindranath */ 331389a36810SAnil Ravindranath static void pmcraid_free_sglist(struct pmcraid_sglist *sglist) 331489a36810SAnil Ravindranath { 331589a36810SAnil Ravindranath int i; 331689a36810SAnil Ravindranath 331789a36810SAnil Ravindranath for (i = 0; i < sglist->num_sg; i++) 331889a36810SAnil Ravindranath __free_pages(sg_page(&(sglist->scatterlist[i])), 331989a36810SAnil Ravindranath sglist->order); 332089a36810SAnil Ravindranath 332189a36810SAnil Ravindranath kfree(sglist); 332289a36810SAnil Ravindranath } 332389a36810SAnil Ravindranath 332489a36810SAnil Ravindranath /** 332589a36810SAnil Ravindranath * pmcraid_alloc_sglist - Allocates memory for a SG list 332689a36810SAnil Ravindranath * @buflen: buffer length 332789a36810SAnil Ravindranath * 332889a36810SAnil Ravindranath * Allocates a DMA'able buffer in chunks and assembles a scatter/gather 332989a36810SAnil Ravindranath * list. 333089a36810SAnil Ravindranath * 333189a36810SAnil Ravindranath * Return value 333289a36810SAnil Ravindranath * pointer to sglist / NULL on failure 333389a36810SAnil Ravindranath */ 333489a36810SAnil Ravindranath static struct pmcraid_sglist *pmcraid_alloc_sglist(int buflen) 333589a36810SAnil Ravindranath { 333689a36810SAnil Ravindranath struct pmcraid_sglist *sglist; 333789a36810SAnil Ravindranath struct scatterlist *scatterlist; 333889a36810SAnil Ravindranath struct page *page; 333989a36810SAnil Ravindranath int num_elem, i, j; 334089a36810SAnil Ravindranath int sg_size; 334189a36810SAnil Ravindranath int order; 334289a36810SAnil Ravindranath int bsize_elem; 334389a36810SAnil Ravindranath 334489a36810SAnil Ravindranath sg_size = buflen / (PMCRAID_MAX_IOADLS - 1); 334589a36810SAnil Ravindranath order = (sg_size > 0) ? get_order(sg_size) : 0; 334689a36810SAnil Ravindranath bsize_elem = PAGE_SIZE * (1 << order); 334789a36810SAnil Ravindranath 334889a36810SAnil Ravindranath /* Determine the actual number of sg entries needed */ 334989a36810SAnil Ravindranath if (buflen % bsize_elem) 335089a36810SAnil Ravindranath num_elem = (buflen / bsize_elem) + 1; 335189a36810SAnil Ravindranath else 335289a36810SAnil Ravindranath num_elem = buflen / bsize_elem; 335389a36810SAnil Ravindranath 335489a36810SAnil Ravindranath /* Allocate a scatter/gather list for the DMA */ 335589a36810SAnil Ravindranath sglist = kzalloc(sizeof(struct pmcraid_sglist) + 335689a36810SAnil Ravindranath (sizeof(struct scatterlist) * (num_elem - 1)), 335789a36810SAnil Ravindranath GFP_KERNEL); 335889a36810SAnil Ravindranath 335989a36810SAnil Ravindranath if (sglist == NULL) 336089a36810SAnil Ravindranath return NULL; 336189a36810SAnil Ravindranath 336289a36810SAnil Ravindranath scatterlist = sglist->scatterlist; 336389a36810SAnil Ravindranath sg_init_table(scatterlist, num_elem); 336489a36810SAnil Ravindranath sglist->order = order; 336589a36810SAnil Ravindranath sglist->num_sg = num_elem; 336689a36810SAnil Ravindranath sg_size = buflen; 336789a36810SAnil Ravindranath 336889a36810SAnil Ravindranath for (i = 0; i < num_elem; i++) { 3369592488a3SAnil Ravindranath page = alloc_pages(GFP_KERNEL|GFP_DMA|__GFP_ZERO, order); 337089a36810SAnil Ravindranath if (!page) { 337189a36810SAnil Ravindranath for (j = i - 1; j >= 0; j--) 337289a36810SAnil Ravindranath __free_pages(sg_page(&scatterlist[j]), order); 337389a36810SAnil Ravindranath kfree(sglist); 337489a36810SAnil Ravindranath return NULL; 337589a36810SAnil Ravindranath } 337689a36810SAnil Ravindranath 337789a36810SAnil Ravindranath sg_set_page(&scatterlist[i], page, 337889a36810SAnil Ravindranath sg_size < bsize_elem ? sg_size : bsize_elem, 0); 337989a36810SAnil Ravindranath sg_size -= bsize_elem; 338089a36810SAnil Ravindranath } 338189a36810SAnil Ravindranath 338289a36810SAnil Ravindranath return sglist; 338389a36810SAnil Ravindranath } 338489a36810SAnil Ravindranath 338589a36810SAnil Ravindranath /** 338689a36810SAnil Ravindranath * pmcraid_copy_sglist - Copy user buffer to kernel buffer's SG list 338789a36810SAnil Ravindranath * @sglist: scatter/gather list pointer 338889a36810SAnil Ravindranath * @buffer: buffer pointer 338989a36810SAnil Ravindranath * @len: buffer length 339089a36810SAnil Ravindranath * @direction: data transfer direction 339189a36810SAnil Ravindranath * 339289a36810SAnil Ravindranath * Copy a user buffer into a buffer allocated by pmcraid_alloc_sglist 339389a36810SAnil Ravindranath * 339489a36810SAnil Ravindranath * Return value: 339589a36810SAnil Ravindranath * 0 on success / other on failure 339689a36810SAnil Ravindranath */ 339789a36810SAnil Ravindranath static int pmcraid_copy_sglist( 339889a36810SAnil Ravindranath struct pmcraid_sglist *sglist, 339989a36810SAnil Ravindranath unsigned long buffer, 340089a36810SAnil Ravindranath u32 len, 340189a36810SAnil Ravindranath int direction 340289a36810SAnil Ravindranath ) 340389a36810SAnil Ravindranath { 340489a36810SAnil Ravindranath struct scatterlist *scatterlist; 340589a36810SAnil Ravindranath void *kaddr; 340689a36810SAnil Ravindranath int bsize_elem; 340789a36810SAnil Ravindranath int i; 340889a36810SAnil Ravindranath int rc = 0; 340989a36810SAnil Ravindranath 341089a36810SAnil Ravindranath /* Determine the actual number of bytes per element */ 341189a36810SAnil Ravindranath bsize_elem = PAGE_SIZE * (1 << sglist->order); 341289a36810SAnil Ravindranath 341389a36810SAnil Ravindranath scatterlist = sglist->scatterlist; 341489a36810SAnil Ravindranath 341589a36810SAnil Ravindranath for (i = 0; i < (len / bsize_elem); i++, buffer += bsize_elem) { 341689a36810SAnil Ravindranath struct page *page = sg_page(&scatterlist[i]); 341789a36810SAnil Ravindranath 341889a36810SAnil Ravindranath kaddr = kmap(page); 341989a36810SAnil Ravindranath if (direction == DMA_TO_DEVICE) 342089a36810SAnil Ravindranath rc = __copy_from_user(kaddr, 342189a36810SAnil Ravindranath (void *)buffer, 342289a36810SAnil Ravindranath bsize_elem); 342389a36810SAnil Ravindranath else 342489a36810SAnil Ravindranath rc = __copy_to_user((void *)buffer, kaddr, bsize_elem); 342589a36810SAnil Ravindranath 342689a36810SAnil Ravindranath kunmap(page); 342789a36810SAnil Ravindranath 342889a36810SAnil Ravindranath if (rc) { 342989a36810SAnil Ravindranath pmcraid_err("failed to copy user data into sg list\n"); 343089a36810SAnil Ravindranath return -EFAULT; 343189a36810SAnil Ravindranath } 343289a36810SAnil Ravindranath 343389a36810SAnil Ravindranath scatterlist[i].length = bsize_elem; 343489a36810SAnil Ravindranath } 343589a36810SAnil Ravindranath 343689a36810SAnil Ravindranath if (len % bsize_elem) { 343789a36810SAnil Ravindranath struct page *page = sg_page(&scatterlist[i]); 343889a36810SAnil Ravindranath 343989a36810SAnil Ravindranath kaddr = kmap(page); 344089a36810SAnil Ravindranath 344189a36810SAnil Ravindranath if (direction == DMA_TO_DEVICE) 344289a36810SAnil Ravindranath rc = __copy_from_user(kaddr, 344389a36810SAnil Ravindranath (void *)buffer, 344489a36810SAnil Ravindranath len % bsize_elem); 344589a36810SAnil Ravindranath else 344689a36810SAnil Ravindranath rc = __copy_to_user((void *)buffer, 344789a36810SAnil Ravindranath kaddr, 344889a36810SAnil Ravindranath len % bsize_elem); 344989a36810SAnil Ravindranath 345089a36810SAnil Ravindranath kunmap(page); 345189a36810SAnil Ravindranath 345289a36810SAnil Ravindranath scatterlist[i].length = len % bsize_elem; 345389a36810SAnil Ravindranath } 345489a36810SAnil Ravindranath 345589a36810SAnil Ravindranath if (rc) { 345689a36810SAnil Ravindranath pmcraid_err("failed to copy user data into sg list\n"); 345789a36810SAnil Ravindranath rc = -EFAULT; 345889a36810SAnil Ravindranath } 345989a36810SAnil Ravindranath 346089a36810SAnil Ravindranath return rc; 346189a36810SAnil Ravindranath } 346289a36810SAnil Ravindranath 346389a36810SAnil Ravindranath /** 346489a36810SAnil Ravindranath * pmcraid_queuecommand - Queue a mid-layer request 346589a36810SAnil Ravindranath * @scsi_cmd: scsi command struct 346689a36810SAnil Ravindranath * @done: done function 346789a36810SAnil Ravindranath * 346889a36810SAnil Ravindranath * This function queues a request generated by the mid-layer. Midlayer calls 346989a36810SAnil Ravindranath * this routine within host->lock. Some of the functions called by queuecommand 347089a36810SAnil Ravindranath * would use cmd block queue locks (free_pool_lock and pending_pool_lock) 347189a36810SAnil Ravindranath * 347289a36810SAnil Ravindranath * Return value: 347389a36810SAnil Ravindranath * 0 on success 347489a36810SAnil Ravindranath * SCSI_MLQUEUE_DEVICE_BUSY if device is busy 347589a36810SAnil Ravindranath * SCSI_MLQUEUE_HOST_BUSY if host is busy 347689a36810SAnil Ravindranath */ 3477f281233dSJeff Garzik static int pmcraid_queuecommand_lck( 347889a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd, 347989a36810SAnil Ravindranath void (*done) (struct scsi_cmnd *) 348089a36810SAnil Ravindranath ) 348189a36810SAnil Ravindranath { 348289a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 348389a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 348489a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb; 348589a36810SAnil Ravindranath struct pmcraid_cmd *cmd; 3486c20c4267SAnil Ravindranath u32 fw_version; 348789a36810SAnil Ravindranath int rc = 0; 348889a36810SAnil Ravindranath 348989a36810SAnil Ravindranath pinstance = 349089a36810SAnil Ravindranath (struct pmcraid_instance *)scsi_cmd->device->host->hostdata; 3491c20c4267SAnil Ravindranath fw_version = be16_to_cpu(pinstance->inq_data->fw_version); 349289a36810SAnil Ravindranath scsi_cmd->scsi_done = done; 349389a36810SAnil Ravindranath res = scsi_cmd->device->hostdata; 349489a36810SAnil Ravindranath scsi_cmd->result = (DID_OK << 16); 349589a36810SAnil Ravindranath 349689a36810SAnil Ravindranath /* if adapter is marked as dead, set result to DID_NO_CONNECT complete 349789a36810SAnil Ravindranath * the command 349889a36810SAnil Ravindranath */ 349989a36810SAnil Ravindranath if (pinstance->ioa_state == IOA_STATE_DEAD) { 350089a36810SAnil Ravindranath pmcraid_info("IOA is dead, but queuecommand is scheduled\n"); 350189a36810SAnil Ravindranath scsi_cmd->result = (DID_NO_CONNECT << 16); 350289a36810SAnil Ravindranath scsi_cmd->scsi_done(scsi_cmd); 350389a36810SAnil Ravindranath return 0; 350489a36810SAnil Ravindranath } 350589a36810SAnil Ravindranath 350689a36810SAnil Ravindranath /* If IOA reset is in progress, can't queue the commands */ 350789a36810SAnil Ravindranath if (pinstance->ioa_reset_in_progress) 350889a36810SAnil Ravindranath return SCSI_MLQUEUE_HOST_BUSY; 350989a36810SAnil Ravindranath 3510c20c4267SAnil Ravindranath /* Firmware doesn't support SYNCHRONIZE_CACHE command (0x35), complete 3511c20c4267SAnil Ravindranath * the command here itself with success return 3512c20c4267SAnil Ravindranath */ 3513c20c4267SAnil Ravindranath if (scsi_cmd->cmnd[0] == SYNCHRONIZE_CACHE) { 3514c20c4267SAnil Ravindranath pmcraid_info("SYNC_CACHE(0x35), completing in driver itself\n"); 3515c20c4267SAnil Ravindranath scsi_cmd->scsi_done(scsi_cmd); 3516c20c4267SAnil Ravindranath return 0; 3517c20c4267SAnil Ravindranath } 3518c20c4267SAnil Ravindranath 351989a36810SAnil Ravindranath /* initialize the command and IOARCB to be sent to IOA */ 352089a36810SAnil Ravindranath cmd = pmcraid_get_free_cmd(pinstance); 352189a36810SAnil Ravindranath 352289a36810SAnil Ravindranath if (cmd == NULL) { 352389a36810SAnil Ravindranath pmcraid_err("free command block is not available\n"); 352489a36810SAnil Ravindranath return SCSI_MLQUEUE_HOST_BUSY; 352589a36810SAnil Ravindranath } 352689a36810SAnil Ravindranath 352789a36810SAnil Ravindranath cmd->scsi_cmd = scsi_cmd; 352889a36810SAnil Ravindranath ioarcb = &(cmd->ioa_cb->ioarcb); 352989a36810SAnil Ravindranath memcpy(ioarcb->cdb, scsi_cmd->cmnd, scsi_cmd->cmd_len); 353089a36810SAnil Ravindranath ioarcb->resource_handle = res->cfg_entry.resource_handle; 353189a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_SCSI; 353289a36810SAnil Ravindranath 3533c20c4267SAnil Ravindranath /* set hrrq number where the IOA should respond to. Note that all cmds 3534c20c4267SAnil Ravindranath * generated internally uses hrrq_id 0, exception to this is the cmd 3535c20c4267SAnil Ravindranath * block of scsi_cmd which is re-used (e.g. cancel/abort), which uses 3536c20c4267SAnil Ravindranath * hrrq_id assigned here in queuecommand 3537c20c4267SAnil Ravindranath */ 3538c20c4267SAnil Ravindranath ioarcb->hrrq_id = atomic_add_return(1, &(pinstance->last_message_id)) % 3539c20c4267SAnil Ravindranath pinstance->num_hrrq; 354089a36810SAnil Ravindranath cmd->cmd_done = pmcraid_io_done; 354189a36810SAnil Ravindranath 354289a36810SAnil Ravindranath if (RES_IS_GSCSI(res->cfg_entry) || RES_IS_VSET(res->cfg_entry)) { 354389a36810SAnil Ravindranath if (scsi_cmd->underflow == 0) 354489a36810SAnil Ravindranath ioarcb->request_flags0 |= INHIBIT_UL_CHECK; 354589a36810SAnil Ravindranath 354689a36810SAnil Ravindranath if (res->sync_reqd) { 354789a36810SAnil Ravindranath ioarcb->request_flags0 |= SYNC_COMPLETE; 354889a36810SAnil Ravindranath res->sync_reqd = 0; 354989a36810SAnil Ravindranath } 355089a36810SAnil Ravindranath 355189a36810SAnil Ravindranath ioarcb->request_flags0 |= NO_LINK_DESCS; 355289a36810SAnil Ravindranath ioarcb->request_flags1 |= pmcraid_task_attributes(scsi_cmd); 355389a36810SAnil Ravindranath 355489a36810SAnil Ravindranath if (RES_IS_GSCSI(res->cfg_entry)) 355589a36810SAnil Ravindranath ioarcb->request_flags1 |= DELAY_AFTER_RESET; 355689a36810SAnil Ravindranath } 355789a36810SAnil Ravindranath 355889a36810SAnil Ravindranath rc = pmcraid_build_ioadl(pinstance, cmd); 355989a36810SAnil Ravindranath 356089a36810SAnil Ravindranath pmcraid_info("command (%d) CDB[0] = %x for %x:%x:%x:%x\n", 356189a36810SAnil Ravindranath le32_to_cpu(ioarcb->response_handle) >> 2, 356289a36810SAnil Ravindranath scsi_cmd->cmnd[0], pinstance->host->unique_id, 356389a36810SAnil Ravindranath RES_IS_VSET(res->cfg_entry) ? PMCRAID_VSET_BUS_ID : 356489a36810SAnil Ravindranath PMCRAID_PHYS_BUS_ID, 356589a36810SAnil Ravindranath RES_IS_VSET(res->cfg_entry) ? 3566c20c4267SAnil Ravindranath (fw_version <= PMCRAID_FW_VERSION_1 ? 356789a36810SAnil Ravindranath res->cfg_entry.unique_flags1 : 3568c20c4267SAnil Ravindranath res->cfg_entry.array_id & 0xFF) : 356989a36810SAnil Ravindranath RES_TARGET(res->cfg_entry.resource_address), 357089a36810SAnil Ravindranath RES_LUN(res->cfg_entry.resource_address)); 357189a36810SAnil Ravindranath 357289a36810SAnil Ravindranath if (likely(rc == 0)) { 357389a36810SAnil Ravindranath _pmcraid_fire_command(cmd); 357489a36810SAnil Ravindranath } else { 357589a36810SAnil Ravindranath pmcraid_err("queuecommand could not build ioadl\n"); 357689a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 357789a36810SAnil Ravindranath rc = SCSI_MLQUEUE_HOST_BUSY; 357889a36810SAnil Ravindranath } 357989a36810SAnil Ravindranath 358089a36810SAnil Ravindranath return rc; 358189a36810SAnil Ravindranath } 358289a36810SAnil Ravindranath 3583f281233dSJeff Garzik static DEF_SCSI_QCMD(pmcraid_queuecommand) 3584f281233dSJeff Garzik 358589a36810SAnil Ravindranath /** 358689a36810SAnil Ravindranath * pmcraid_open -char node "open" entry, allowed only users with admin access 358789a36810SAnil Ravindranath */ 358889a36810SAnil Ravindranath static int pmcraid_chr_open(struct inode *inode, struct file *filep) 358989a36810SAnil Ravindranath { 359089a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 359189a36810SAnil Ravindranath 359289a36810SAnil Ravindranath if (!capable(CAP_SYS_ADMIN)) 359389a36810SAnil Ravindranath return -EACCES; 359489a36810SAnil Ravindranath 359589a36810SAnil Ravindranath /* Populate adapter instance * pointer for use by ioctl */ 359689a36810SAnil Ravindranath pinstance = container_of(inode->i_cdev, struct pmcraid_instance, cdev); 359789a36810SAnil Ravindranath filep->private_data = pinstance; 359889a36810SAnil Ravindranath 359989a36810SAnil Ravindranath return 0; 360089a36810SAnil Ravindranath } 360189a36810SAnil Ravindranath 360289a36810SAnil Ravindranath /** 360389a36810SAnil Ravindranath * pmcraid_release - char node "release" entry point 360489a36810SAnil Ravindranath */ 360589a36810SAnil Ravindranath static int pmcraid_chr_release(struct inode *inode, struct file *filep) 360689a36810SAnil Ravindranath { 3607660bdddbSCyril Jayaprakash struct pmcraid_instance *pinstance = filep->private_data; 360889a36810SAnil Ravindranath 360989a36810SAnil Ravindranath filep->private_data = NULL; 361089a36810SAnil Ravindranath fasync_helper(-1, filep, 0, &pinstance->aen_queue); 361189a36810SAnil Ravindranath 361289a36810SAnil Ravindranath return 0; 361389a36810SAnil Ravindranath } 361489a36810SAnil Ravindranath 361589a36810SAnil Ravindranath /** 361689a36810SAnil Ravindranath * pmcraid_fasync - Async notifier registration from applications 361789a36810SAnil Ravindranath * 361889a36810SAnil Ravindranath * This function adds the calling process to a driver global queue. When an 361989a36810SAnil Ravindranath * event occurs, SIGIO will be sent to all processes in this queue. 362089a36810SAnil Ravindranath */ 362189a36810SAnil Ravindranath static int pmcraid_chr_fasync(int fd, struct file *filep, int mode) 362289a36810SAnil Ravindranath { 362389a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 362489a36810SAnil Ravindranath int rc; 362589a36810SAnil Ravindranath 3626660bdddbSCyril Jayaprakash pinstance = filep->private_data; 362789a36810SAnil Ravindranath mutex_lock(&pinstance->aen_queue_lock); 362889a36810SAnil Ravindranath rc = fasync_helper(fd, filep, mode, &pinstance->aen_queue); 362989a36810SAnil Ravindranath mutex_unlock(&pinstance->aen_queue_lock); 363089a36810SAnil Ravindranath 363189a36810SAnil Ravindranath return rc; 363289a36810SAnil Ravindranath } 363389a36810SAnil Ravindranath 363489a36810SAnil Ravindranath 363589a36810SAnil Ravindranath /** 363689a36810SAnil Ravindranath * pmcraid_build_passthrough_ioadls - builds SG elements for passthrough 363789a36810SAnil Ravindranath * commands sent over IOCTL interface 363889a36810SAnil Ravindranath * 363989a36810SAnil Ravindranath * @cmd : pointer to struct pmcraid_cmd 364089a36810SAnil Ravindranath * @buflen : length of the request buffer 364189a36810SAnil Ravindranath * @direction : data transfer direction 364289a36810SAnil Ravindranath * 364389a36810SAnil Ravindranath * Return value 3644af901ca1SAndré Goddard Rosa * 0 on success, non-zero error code on failure 364589a36810SAnil Ravindranath */ 364689a36810SAnil Ravindranath static int pmcraid_build_passthrough_ioadls( 364789a36810SAnil Ravindranath struct pmcraid_cmd *cmd, 364889a36810SAnil Ravindranath int buflen, 364989a36810SAnil Ravindranath int direction 365089a36810SAnil Ravindranath ) 365189a36810SAnil Ravindranath { 365289a36810SAnil Ravindranath struct pmcraid_sglist *sglist = NULL; 365389a36810SAnil Ravindranath struct scatterlist *sg = NULL; 365489a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 365589a36810SAnil Ravindranath struct pmcraid_ioadl_desc *ioadl; 365689a36810SAnil Ravindranath int i; 365789a36810SAnil Ravindranath 365889a36810SAnil Ravindranath sglist = pmcraid_alloc_sglist(buflen); 365989a36810SAnil Ravindranath 366089a36810SAnil Ravindranath if (!sglist) { 366189a36810SAnil Ravindranath pmcraid_err("can't allocate memory for passthrough SGls\n"); 366289a36810SAnil Ravindranath return -ENOMEM; 366389a36810SAnil Ravindranath } 366489a36810SAnil Ravindranath 366589a36810SAnil Ravindranath sglist->num_dma_sg = pci_map_sg(cmd->drv_inst->pdev, 366689a36810SAnil Ravindranath sglist->scatterlist, 366789a36810SAnil Ravindranath sglist->num_sg, direction); 366889a36810SAnil Ravindranath 366989a36810SAnil Ravindranath if (!sglist->num_dma_sg || sglist->num_dma_sg > PMCRAID_MAX_IOADLS) { 367089a36810SAnil Ravindranath dev_err(&cmd->drv_inst->pdev->dev, 367189a36810SAnil Ravindranath "Failed to map passthrough buffer!\n"); 367289a36810SAnil Ravindranath pmcraid_free_sglist(sglist); 367389a36810SAnil Ravindranath return -EIO; 367489a36810SAnil Ravindranath } 367589a36810SAnil Ravindranath 367689a36810SAnil Ravindranath cmd->sglist = sglist; 367789a36810SAnil Ravindranath ioarcb->request_flags0 |= NO_LINK_DESCS; 367889a36810SAnil Ravindranath 367989a36810SAnil Ravindranath ioadl = pmcraid_init_ioadls(cmd, sglist->num_dma_sg); 368089a36810SAnil Ravindranath 368189a36810SAnil Ravindranath /* Initialize IOADL descriptor addresses */ 368289a36810SAnil Ravindranath for_each_sg(sglist->scatterlist, sg, sglist->num_dma_sg, i) { 368389a36810SAnil Ravindranath ioadl[i].data_len = cpu_to_le32(sg_dma_len(sg)); 368489a36810SAnil Ravindranath ioadl[i].address = cpu_to_le64(sg_dma_address(sg)); 368589a36810SAnil Ravindranath ioadl[i].flags = 0; 368689a36810SAnil Ravindranath } 368789a36810SAnil Ravindranath 368889a36810SAnil Ravindranath /* setup the last descriptor */ 368988197966SAnil Ravindranath ioadl[i - 1].flags = IOADL_FLAGS_LAST_DESC; 369089a36810SAnil Ravindranath 369189a36810SAnil Ravindranath return 0; 369289a36810SAnil Ravindranath } 369389a36810SAnil Ravindranath 369489a36810SAnil Ravindranath 369589a36810SAnil Ravindranath /** 369689a36810SAnil Ravindranath * pmcraid_release_passthrough_ioadls - release passthrough ioadls 369789a36810SAnil Ravindranath * 369889a36810SAnil Ravindranath * @cmd: pointer to struct pmcraid_cmd for which ioadls were allocated 369989a36810SAnil Ravindranath * @buflen: size of the request buffer 370089a36810SAnil Ravindranath * @direction: data transfer direction 370189a36810SAnil Ravindranath * 370289a36810SAnil Ravindranath * Return value 3703af901ca1SAndré Goddard Rosa * 0 on success, non-zero error code on failure 370489a36810SAnil Ravindranath */ 370589a36810SAnil Ravindranath static void pmcraid_release_passthrough_ioadls( 370689a36810SAnil Ravindranath struct pmcraid_cmd *cmd, 370789a36810SAnil Ravindranath int buflen, 370889a36810SAnil Ravindranath int direction 370989a36810SAnil Ravindranath ) 371089a36810SAnil Ravindranath { 371189a36810SAnil Ravindranath struct pmcraid_sglist *sglist = cmd->sglist; 371289a36810SAnil Ravindranath 371389a36810SAnil Ravindranath if (buflen > 0) { 371489a36810SAnil Ravindranath pci_unmap_sg(cmd->drv_inst->pdev, 371589a36810SAnil Ravindranath sglist->scatterlist, 371689a36810SAnil Ravindranath sglist->num_sg, 371789a36810SAnil Ravindranath direction); 371889a36810SAnil Ravindranath pmcraid_free_sglist(sglist); 371989a36810SAnil Ravindranath cmd->sglist = NULL; 372089a36810SAnil Ravindranath } 372189a36810SAnil Ravindranath } 372289a36810SAnil Ravindranath 372389a36810SAnil Ravindranath /** 372489a36810SAnil Ravindranath * pmcraid_ioctl_passthrough - handling passthrough IOCTL commands 372589a36810SAnil Ravindranath * 372689a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 372789a36810SAnil Ravindranath * @cmd: ioctl code 372889a36810SAnil Ravindranath * @arg: pointer to pmcraid_passthrough_buffer user buffer 372989a36810SAnil Ravindranath * 373089a36810SAnil Ravindranath * Return value 3731af901ca1SAndré Goddard Rosa * 0 on success, non-zero error code on failure 373289a36810SAnil Ravindranath */ 373389a36810SAnil Ravindranath static long pmcraid_ioctl_passthrough( 373489a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 373589a36810SAnil Ravindranath unsigned int ioctl_cmd, 373689a36810SAnil Ravindranath unsigned int buflen, 373789a36810SAnil Ravindranath unsigned long arg 373889a36810SAnil Ravindranath ) 373989a36810SAnil Ravindranath { 374089a36810SAnil Ravindranath struct pmcraid_passthrough_ioctl_buffer *buffer; 374189a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb; 374289a36810SAnil Ravindranath struct pmcraid_cmd *cmd; 374389a36810SAnil Ravindranath struct pmcraid_cmd *cancel_cmd; 374489a36810SAnil Ravindranath unsigned long request_buffer; 374589a36810SAnil Ravindranath unsigned long request_offset; 374689a36810SAnil Ravindranath unsigned long lock_flags; 3747592488a3SAnil Ravindranath void *ioasa; 3748c20c4267SAnil Ravindranath u32 ioasc; 374989a36810SAnil Ravindranath int request_size; 375089a36810SAnil Ravindranath int buffer_size; 375189a36810SAnil Ravindranath u8 access, direction; 375289a36810SAnil Ravindranath int rc = 0; 375389a36810SAnil Ravindranath 375489a36810SAnil Ravindranath /* If IOA reset is in progress, wait 10 secs for reset to complete */ 375589a36810SAnil Ravindranath if (pinstance->ioa_reset_in_progress) { 375689a36810SAnil Ravindranath rc = wait_event_interruptible_timeout( 375789a36810SAnil Ravindranath pinstance->reset_wait_q, 375889a36810SAnil Ravindranath !pinstance->ioa_reset_in_progress, 375989a36810SAnil Ravindranath msecs_to_jiffies(10000)); 376089a36810SAnil Ravindranath 376189a36810SAnil Ravindranath if (!rc) 376289a36810SAnil Ravindranath return -ETIMEDOUT; 376389a36810SAnil Ravindranath else if (rc < 0) 376489a36810SAnil Ravindranath return -ERESTARTSYS; 376589a36810SAnil Ravindranath } 376689a36810SAnil Ravindranath 376789a36810SAnil Ravindranath /* If adapter is not in operational state, return error */ 376889a36810SAnil Ravindranath if (pinstance->ioa_state != IOA_STATE_OPERATIONAL) { 376989a36810SAnil Ravindranath pmcraid_err("IOA is not operational\n"); 377089a36810SAnil Ravindranath return -ENOTTY; 377189a36810SAnil Ravindranath } 377289a36810SAnil Ravindranath 377389a36810SAnil Ravindranath buffer_size = sizeof(struct pmcraid_passthrough_ioctl_buffer); 377489a36810SAnil Ravindranath buffer = kmalloc(buffer_size, GFP_KERNEL); 377589a36810SAnil Ravindranath 377689a36810SAnil Ravindranath if (!buffer) { 377789a36810SAnil Ravindranath pmcraid_err("no memory for passthrough buffer\n"); 377889a36810SAnil Ravindranath return -ENOMEM; 377989a36810SAnil Ravindranath } 378089a36810SAnil Ravindranath 378189a36810SAnil Ravindranath request_offset = 378289a36810SAnil Ravindranath offsetof(struct pmcraid_passthrough_ioctl_buffer, request_buffer); 378389a36810SAnil Ravindranath 378489a36810SAnil Ravindranath request_buffer = arg + request_offset; 378589a36810SAnil Ravindranath 378689a36810SAnil Ravindranath rc = __copy_from_user(buffer, 378789a36810SAnil Ravindranath (struct pmcraid_passthrough_ioctl_buffer *) arg, 378889a36810SAnil Ravindranath sizeof(struct pmcraid_passthrough_ioctl_buffer)); 3789592488a3SAnil Ravindranath 3790592488a3SAnil Ravindranath ioasa = 3791592488a3SAnil Ravindranath (void *)(arg + 3792592488a3SAnil Ravindranath offsetof(struct pmcraid_passthrough_ioctl_buffer, ioasa)); 3793592488a3SAnil Ravindranath 379489a36810SAnil Ravindranath if (rc) { 379589a36810SAnil Ravindranath pmcraid_err("ioctl: can't copy passthrough buffer\n"); 379689a36810SAnil Ravindranath rc = -EFAULT; 379789a36810SAnil Ravindranath goto out_free_buffer; 379889a36810SAnil Ravindranath } 379989a36810SAnil Ravindranath 380089a36810SAnil Ravindranath request_size = buffer->ioarcb.data_transfer_length; 380189a36810SAnil Ravindranath 380289a36810SAnil Ravindranath if (buffer->ioarcb.request_flags0 & TRANSFER_DIR_WRITE) { 380389a36810SAnil Ravindranath access = VERIFY_READ; 380489a36810SAnil Ravindranath direction = DMA_TO_DEVICE; 380589a36810SAnil Ravindranath } else { 380689a36810SAnil Ravindranath access = VERIFY_WRITE; 380789a36810SAnil Ravindranath direction = DMA_FROM_DEVICE; 380889a36810SAnil Ravindranath } 380989a36810SAnil Ravindranath 381089a36810SAnil Ravindranath if (request_size > 0) { 381189a36810SAnil Ravindranath rc = access_ok(access, arg, request_offset + request_size); 381289a36810SAnil Ravindranath 381389a36810SAnil Ravindranath if (!rc) { 381489a36810SAnil Ravindranath rc = -EFAULT; 381589a36810SAnil Ravindranath goto out_free_buffer; 381689a36810SAnil Ravindranath } 38175f6279daSDan Rosenberg } else if (request_size < 0) { 38185f6279daSDan Rosenberg rc = -EINVAL; 38195f6279daSDan Rosenberg goto out_free_buffer; 382089a36810SAnil Ravindranath } 382189a36810SAnil Ravindranath 382289a36810SAnil Ravindranath /* check if we have any additional command parameters */ 382389a36810SAnil Ravindranath if (buffer->ioarcb.add_cmd_param_length > PMCRAID_ADD_CMD_PARAM_LEN) { 382489a36810SAnil Ravindranath rc = -EINVAL; 382589a36810SAnil Ravindranath goto out_free_buffer; 382689a36810SAnil Ravindranath } 382789a36810SAnil Ravindranath 382889a36810SAnil Ravindranath cmd = pmcraid_get_free_cmd(pinstance); 382989a36810SAnil Ravindranath 383089a36810SAnil Ravindranath if (!cmd) { 383189a36810SAnil Ravindranath pmcraid_err("free command block is not available\n"); 383289a36810SAnil Ravindranath rc = -ENOMEM; 383389a36810SAnil Ravindranath goto out_free_buffer; 383489a36810SAnil Ravindranath } 383589a36810SAnil Ravindranath 383689a36810SAnil Ravindranath cmd->scsi_cmd = NULL; 383789a36810SAnil Ravindranath ioarcb = &(cmd->ioa_cb->ioarcb); 383889a36810SAnil Ravindranath 383989a36810SAnil Ravindranath /* Copy the user-provided IOARCB stuff field by field */ 384089a36810SAnil Ravindranath ioarcb->resource_handle = buffer->ioarcb.resource_handle; 384189a36810SAnil Ravindranath ioarcb->data_transfer_length = buffer->ioarcb.data_transfer_length; 384289a36810SAnil Ravindranath ioarcb->cmd_timeout = buffer->ioarcb.cmd_timeout; 384389a36810SAnil Ravindranath ioarcb->request_type = buffer->ioarcb.request_type; 384489a36810SAnil Ravindranath ioarcb->request_flags0 = buffer->ioarcb.request_flags0; 384589a36810SAnil Ravindranath ioarcb->request_flags1 = buffer->ioarcb.request_flags1; 384689a36810SAnil Ravindranath memcpy(ioarcb->cdb, buffer->ioarcb.cdb, PMCRAID_MAX_CDB_LEN); 384789a36810SAnil Ravindranath 384889a36810SAnil Ravindranath if (buffer->ioarcb.add_cmd_param_length) { 384989a36810SAnil Ravindranath ioarcb->add_cmd_param_length = 385089a36810SAnil Ravindranath buffer->ioarcb.add_cmd_param_length; 385189a36810SAnil Ravindranath ioarcb->add_cmd_param_offset = 385289a36810SAnil Ravindranath buffer->ioarcb.add_cmd_param_offset; 385389a36810SAnil Ravindranath memcpy(ioarcb->add_data.u.add_cmd_params, 385489a36810SAnil Ravindranath buffer->ioarcb.add_data.u.add_cmd_params, 385589a36810SAnil Ravindranath buffer->ioarcb.add_cmd_param_length); 385689a36810SAnil Ravindranath } 385789a36810SAnil Ravindranath 3858c20c4267SAnil Ravindranath /* set hrrq number where the IOA should respond to. Note that all cmds 3859c20c4267SAnil Ravindranath * generated internally uses hrrq_id 0, exception to this is the cmd 3860c20c4267SAnil Ravindranath * block of scsi_cmd which is re-used (e.g. cancel/abort), which uses 3861c20c4267SAnil Ravindranath * hrrq_id assigned here in queuecommand 3862c20c4267SAnil Ravindranath */ 3863c20c4267SAnil Ravindranath ioarcb->hrrq_id = atomic_add_return(1, &(pinstance->last_message_id)) % 3864c20c4267SAnil Ravindranath pinstance->num_hrrq; 3865c20c4267SAnil Ravindranath 386689a36810SAnil Ravindranath if (request_size) { 386789a36810SAnil Ravindranath rc = pmcraid_build_passthrough_ioadls(cmd, 386889a36810SAnil Ravindranath request_size, 386989a36810SAnil Ravindranath direction); 387089a36810SAnil Ravindranath if (rc) { 387189a36810SAnil Ravindranath pmcraid_err("couldn't build passthrough ioadls\n"); 387289a36810SAnil Ravindranath goto out_free_buffer; 387389a36810SAnil Ravindranath } 387489a36810SAnil Ravindranath } 387589a36810SAnil Ravindranath 387689a36810SAnil Ravindranath /* If data is being written into the device, copy the data from user 387789a36810SAnil Ravindranath * buffers 387889a36810SAnil Ravindranath */ 387989a36810SAnil Ravindranath if (direction == DMA_TO_DEVICE && request_size > 0) { 388089a36810SAnil Ravindranath rc = pmcraid_copy_sglist(cmd->sglist, 388189a36810SAnil Ravindranath request_buffer, 388289a36810SAnil Ravindranath request_size, 388389a36810SAnil Ravindranath direction); 388489a36810SAnil Ravindranath if (rc) { 388589a36810SAnil Ravindranath pmcraid_err("failed to copy user buffer\n"); 388689a36810SAnil Ravindranath goto out_free_sglist; 388789a36810SAnil Ravindranath } 388889a36810SAnil Ravindranath } 388989a36810SAnil Ravindranath 389089a36810SAnil Ravindranath /* passthrough ioctl is a blocking command so, put the user to sleep 389189a36810SAnil Ravindranath * until timeout. Note that a timeout value of 0 means, do timeout. 389289a36810SAnil Ravindranath */ 389389a36810SAnil Ravindranath cmd->cmd_done = pmcraid_internal_done; 389489a36810SAnil Ravindranath init_completion(&cmd->wait_for_completion); 389589a36810SAnil Ravindranath cmd->completion_req = 1; 389689a36810SAnil Ravindranath 389789a36810SAnil Ravindranath pmcraid_info("command(%d) (CDB[0] = %x) for %x\n", 389889a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle) >> 2, 389989a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 390089a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioarcb.resource_handle)); 390189a36810SAnil Ravindranath 390289a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 390389a36810SAnil Ravindranath _pmcraid_fire_command(cmd); 390489a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 390589a36810SAnil Ravindranath 3906c20c4267SAnil Ravindranath /* NOTE ! Remove the below line once abort_task is implemented 3907c20c4267SAnil Ravindranath * in firmware. This line disables ioctl command timeout handling logic 3908c20c4267SAnil Ravindranath * similar to IO command timeout handling, making ioctl commands to wait 3909c20c4267SAnil Ravindranath * until the command completion regardless of timeout value specified in 3910c20c4267SAnil Ravindranath * ioarcb 3911c20c4267SAnil Ravindranath */ 3912c20c4267SAnil Ravindranath buffer->ioarcb.cmd_timeout = 0; 3913c20c4267SAnil Ravindranath 391489a36810SAnil Ravindranath /* If command timeout is specified put caller to wait till that time, 391589a36810SAnil Ravindranath * otherwise it would be blocking wait. If command gets timed out, it 391689a36810SAnil Ravindranath * will be aborted. 391789a36810SAnil Ravindranath */ 391889a36810SAnil Ravindranath if (buffer->ioarcb.cmd_timeout == 0) { 391989a36810SAnil Ravindranath wait_for_completion(&cmd->wait_for_completion); 392089a36810SAnil Ravindranath } else if (!wait_for_completion_timeout( 392189a36810SAnil Ravindranath &cmd->wait_for_completion, 392289a36810SAnil Ravindranath msecs_to_jiffies(buffer->ioarcb.cmd_timeout * 1000))) { 392389a36810SAnil Ravindranath 392489a36810SAnil Ravindranath pmcraid_info("aborting cmd %d (CDB[0] = %x) due to timeout\n", 392589a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle >> 2), 392689a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0]); 392789a36810SAnil Ravindranath 392889a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 392989a36810SAnil Ravindranath cancel_cmd = pmcraid_abort_cmd(cmd); 393089a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 393189a36810SAnil Ravindranath 393289a36810SAnil Ravindranath if (cancel_cmd) { 393389a36810SAnil Ravindranath wait_for_completion(&cancel_cmd->wait_for_completion); 3934c20c4267SAnil Ravindranath ioasc = cancel_cmd->ioa_cb->ioasa.ioasc; 393589a36810SAnil Ravindranath pmcraid_return_cmd(cancel_cmd); 3936c20c4267SAnil Ravindranath 3937c20c4267SAnil Ravindranath /* if abort task couldn't find the command i.e it got 3938c20c4267SAnil Ravindranath * completed prior to aborting, return good completion. 393925985edcSLucas De Marchi * if command got aborted successfully or there was IOA 3940c20c4267SAnil Ravindranath * reset due to abort task itself getting timedout then 3941c20c4267SAnil Ravindranath * return -ETIMEDOUT 3942c20c4267SAnil Ravindranath */ 3943c20c4267SAnil Ravindranath if (ioasc == PMCRAID_IOASC_IOA_WAS_RESET || 3944c20c4267SAnil Ravindranath PMCRAID_IOASC_SENSE_KEY(ioasc) == 0x00) { 3945c20c4267SAnil Ravindranath if (ioasc != PMCRAID_IOASC_GC_IOARCB_NOTFOUND) 3946c20c4267SAnil Ravindranath rc = -ETIMEDOUT; 3947c20c4267SAnil Ravindranath goto out_handle_response; 3948c20c4267SAnil Ravindranath } 394989a36810SAnil Ravindranath } 395089a36810SAnil Ravindranath 3951c20c4267SAnil Ravindranath /* no command block for abort task or abort task failed to abort 3952c20c4267SAnil Ravindranath * the IOARCB, then wait for 150 more seconds and initiate reset 3953c20c4267SAnil Ravindranath * sequence after timeout 3954c20c4267SAnil Ravindranath */ 3955c20c4267SAnil Ravindranath if (!wait_for_completion_timeout( 3956c20c4267SAnil Ravindranath &cmd->wait_for_completion, 3957c20c4267SAnil Ravindranath msecs_to_jiffies(150 * 1000))) { 3958c20c4267SAnil Ravindranath pmcraid_reset_bringup(cmd->drv_inst); 3959c20c4267SAnil Ravindranath rc = -ETIMEDOUT; 3960c20c4267SAnil Ravindranath } 396189a36810SAnil Ravindranath } 396289a36810SAnil Ravindranath 3963c20c4267SAnil Ravindranath out_handle_response: 3964592488a3SAnil Ravindranath /* copy entire IOASA buffer and return IOCTL success. 3965592488a3SAnil Ravindranath * If copying IOASA to user-buffer fails, return 396689a36810SAnil Ravindranath * EFAULT 396789a36810SAnil Ravindranath */ 396889a36810SAnil Ravindranath if (copy_to_user(ioasa, &cmd->ioa_cb->ioasa, 396989a36810SAnil Ravindranath sizeof(struct pmcraid_ioasa))) { 397089a36810SAnil Ravindranath pmcraid_err("failed to copy ioasa buffer to user\n"); 397189a36810SAnil Ravindranath rc = -EFAULT; 397289a36810SAnil Ravindranath } 3973c20c4267SAnil Ravindranath 397489a36810SAnil Ravindranath /* If the data transfer was from device, copy the data onto user 397589a36810SAnil Ravindranath * buffers 397689a36810SAnil Ravindranath */ 397789a36810SAnil Ravindranath else if (direction == DMA_FROM_DEVICE && request_size > 0) { 397889a36810SAnil Ravindranath rc = pmcraid_copy_sglist(cmd->sglist, 397989a36810SAnil Ravindranath request_buffer, 398089a36810SAnil Ravindranath request_size, 398189a36810SAnil Ravindranath direction); 398289a36810SAnil Ravindranath if (rc) { 398389a36810SAnil Ravindranath pmcraid_err("failed to copy user buffer\n"); 398489a36810SAnil Ravindranath rc = -EFAULT; 398589a36810SAnil Ravindranath } 398689a36810SAnil Ravindranath } 398789a36810SAnil Ravindranath 398889a36810SAnil Ravindranath out_free_sglist: 398989a36810SAnil Ravindranath pmcraid_release_passthrough_ioadls(cmd, request_size, direction); 399089a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 399189a36810SAnil Ravindranath 399289a36810SAnil Ravindranath out_free_buffer: 399389a36810SAnil Ravindranath kfree(buffer); 399489a36810SAnil Ravindranath 399589a36810SAnil Ravindranath return rc; 399689a36810SAnil Ravindranath } 399789a36810SAnil Ravindranath 399889a36810SAnil Ravindranath 399989a36810SAnil Ravindranath 400089a36810SAnil Ravindranath 400189a36810SAnil Ravindranath /** 400289a36810SAnil Ravindranath * pmcraid_ioctl_driver - ioctl handler for commands handled by driver itself 400389a36810SAnil Ravindranath * 400489a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 400589a36810SAnil Ravindranath * @cmd: ioctl command passed in 400689a36810SAnil Ravindranath * @buflen: length of user_buffer 400789a36810SAnil Ravindranath * @user_buffer: user buffer pointer 400889a36810SAnil Ravindranath * 400989a36810SAnil Ravindranath * Return Value 401089a36810SAnil Ravindranath * 0 in case of success, otherwise appropriate error code 401189a36810SAnil Ravindranath */ 401289a36810SAnil Ravindranath static long pmcraid_ioctl_driver( 401389a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 401489a36810SAnil Ravindranath unsigned int cmd, 401589a36810SAnil Ravindranath unsigned int buflen, 401689a36810SAnil Ravindranath void __user *user_buffer 401789a36810SAnil Ravindranath ) 401889a36810SAnil Ravindranath { 401989a36810SAnil Ravindranath int rc = -ENOSYS; 402089a36810SAnil Ravindranath 402189a36810SAnil Ravindranath if (!access_ok(VERIFY_READ, user_buffer, _IOC_SIZE(cmd))) { 402289a36810SAnil Ravindranath pmcraid_err("ioctl_driver: access fault in request buffer\n"); 402389a36810SAnil Ravindranath return -EFAULT; 402489a36810SAnil Ravindranath } 402589a36810SAnil Ravindranath 402689a36810SAnil Ravindranath switch (cmd) { 402789a36810SAnil Ravindranath case PMCRAID_IOCTL_RESET_ADAPTER: 402889a36810SAnil Ravindranath pmcraid_reset_bringup(pinstance); 402989a36810SAnil Ravindranath rc = 0; 403089a36810SAnil Ravindranath break; 403189a36810SAnil Ravindranath 403289a36810SAnil Ravindranath default: 403389a36810SAnil Ravindranath break; 403489a36810SAnil Ravindranath } 403589a36810SAnil Ravindranath 403689a36810SAnil Ravindranath return rc; 403789a36810SAnil Ravindranath } 403889a36810SAnil Ravindranath 403989a36810SAnil Ravindranath /** 404089a36810SAnil Ravindranath * pmcraid_check_ioctl_buffer - check for proper access to user buffer 404189a36810SAnil Ravindranath * 404289a36810SAnil Ravindranath * @cmd: ioctl command 404389a36810SAnil Ravindranath * @arg: user buffer 404489a36810SAnil Ravindranath * @hdr: pointer to kernel memory for pmcraid_ioctl_header 404589a36810SAnil Ravindranath * 404689a36810SAnil Ravindranath * Return Value 404789a36810SAnil Ravindranath * negetive error code if there are access issues, otherwise zero. 404889a36810SAnil Ravindranath * Upon success, returns ioctl header copied out of user buffer. 404989a36810SAnil Ravindranath */ 405089a36810SAnil Ravindranath 405189a36810SAnil Ravindranath static int pmcraid_check_ioctl_buffer( 405289a36810SAnil Ravindranath int cmd, 405389a36810SAnil Ravindranath void __user *arg, 405489a36810SAnil Ravindranath struct pmcraid_ioctl_header *hdr 405589a36810SAnil Ravindranath ) 405689a36810SAnil Ravindranath { 405789a36810SAnil Ravindranath int rc = 0; 405889a36810SAnil Ravindranath int access = VERIFY_READ; 405989a36810SAnil Ravindranath 406089a36810SAnil Ravindranath if (copy_from_user(hdr, arg, sizeof(struct pmcraid_ioctl_header))) { 406189a36810SAnil Ravindranath pmcraid_err("couldn't copy ioctl header from user buffer\n"); 406289a36810SAnil Ravindranath return -EFAULT; 406389a36810SAnil Ravindranath } 406489a36810SAnil Ravindranath 406589a36810SAnil Ravindranath /* check for valid driver signature */ 406689a36810SAnil Ravindranath rc = memcmp(hdr->signature, 406789a36810SAnil Ravindranath PMCRAID_IOCTL_SIGNATURE, 406889a36810SAnil Ravindranath sizeof(hdr->signature)); 406989a36810SAnil Ravindranath if (rc) { 407089a36810SAnil Ravindranath pmcraid_err("signature verification failed\n"); 407189a36810SAnil Ravindranath return -EINVAL; 407289a36810SAnil Ravindranath } 407389a36810SAnil Ravindranath 407489a36810SAnil Ravindranath /* check for appropriate buffer access */ 407589a36810SAnil Ravindranath if ((_IOC_DIR(cmd) & _IOC_READ) == _IOC_READ) 407689a36810SAnil Ravindranath access = VERIFY_WRITE; 407789a36810SAnil Ravindranath 407889a36810SAnil Ravindranath rc = access_ok(access, 407989a36810SAnil Ravindranath (arg + sizeof(struct pmcraid_ioctl_header)), 408089a36810SAnil Ravindranath hdr->buffer_length); 408189a36810SAnil Ravindranath if (!rc) { 408289a36810SAnil Ravindranath pmcraid_err("access failed for user buffer of size %d\n", 408389a36810SAnil Ravindranath hdr->buffer_length); 408489a36810SAnil Ravindranath return -EFAULT; 408589a36810SAnil Ravindranath } 408689a36810SAnil Ravindranath 408789a36810SAnil Ravindranath return 0; 408889a36810SAnil Ravindranath } 408989a36810SAnil Ravindranath 409089a36810SAnil Ravindranath /** 409189a36810SAnil Ravindranath * pmcraid_ioctl - char node ioctl entry point 409289a36810SAnil Ravindranath */ 409389a36810SAnil Ravindranath static long pmcraid_chr_ioctl( 409489a36810SAnil Ravindranath struct file *filep, 409589a36810SAnil Ravindranath unsigned int cmd, 409689a36810SAnil Ravindranath unsigned long arg 409789a36810SAnil Ravindranath ) 409889a36810SAnil Ravindranath { 409989a36810SAnil Ravindranath struct pmcraid_instance *pinstance = NULL; 410089a36810SAnil Ravindranath struct pmcraid_ioctl_header *hdr = NULL; 410189a36810SAnil Ravindranath int retval = -ENOTTY; 410289a36810SAnil Ravindranath 410389a36810SAnil Ravindranath hdr = kmalloc(GFP_KERNEL, sizeof(struct pmcraid_ioctl_header)); 410489a36810SAnil Ravindranath 410589a36810SAnil Ravindranath if (!hdr) { 410689a36810SAnil Ravindranath pmcraid_err("faile to allocate memory for ioctl header\n"); 410789a36810SAnil Ravindranath return -ENOMEM; 410889a36810SAnil Ravindranath } 410989a36810SAnil Ravindranath 411089a36810SAnil Ravindranath retval = pmcraid_check_ioctl_buffer(cmd, (void *)arg, hdr); 411189a36810SAnil Ravindranath 411289a36810SAnil Ravindranath if (retval) { 411389a36810SAnil Ravindranath pmcraid_info("chr_ioctl: header check failed\n"); 411489a36810SAnil Ravindranath kfree(hdr); 411589a36810SAnil Ravindranath return retval; 411689a36810SAnil Ravindranath } 411789a36810SAnil Ravindranath 4118660bdddbSCyril Jayaprakash pinstance = filep->private_data; 411989a36810SAnil Ravindranath 412089a36810SAnil Ravindranath if (!pinstance) { 412189a36810SAnil Ravindranath pmcraid_info("adapter instance is not found\n"); 412289a36810SAnil Ravindranath kfree(hdr); 412389a36810SAnil Ravindranath return -ENOTTY; 412489a36810SAnil Ravindranath } 412589a36810SAnil Ravindranath 412689a36810SAnil Ravindranath switch (_IOC_TYPE(cmd)) { 412789a36810SAnil Ravindranath 412889a36810SAnil Ravindranath case PMCRAID_PASSTHROUGH_IOCTL: 412989a36810SAnil Ravindranath /* If ioctl code is to download microcode, we need to block 413089a36810SAnil Ravindranath * mid-layer requests. 413189a36810SAnil Ravindranath */ 413289a36810SAnil Ravindranath if (cmd == PMCRAID_IOCTL_DOWNLOAD_MICROCODE) 413389a36810SAnil Ravindranath scsi_block_requests(pinstance->host); 413489a36810SAnil Ravindranath 413589a36810SAnil Ravindranath retval = pmcraid_ioctl_passthrough(pinstance, 413689a36810SAnil Ravindranath cmd, 413789a36810SAnil Ravindranath hdr->buffer_length, 413889a36810SAnil Ravindranath arg); 413989a36810SAnil Ravindranath 414089a36810SAnil Ravindranath if (cmd == PMCRAID_IOCTL_DOWNLOAD_MICROCODE) 414189a36810SAnil Ravindranath scsi_unblock_requests(pinstance->host); 414289a36810SAnil Ravindranath break; 414389a36810SAnil Ravindranath 414489a36810SAnil Ravindranath case PMCRAID_DRIVER_IOCTL: 414589a36810SAnil Ravindranath arg += sizeof(struct pmcraid_ioctl_header); 414689a36810SAnil Ravindranath retval = pmcraid_ioctl_driver(pinstance, 414789a36810SAnil Ravindranath cmd, 414889a36810SAnil Ravindranath hdr->buffer_length, 414989a36810SAnil Ravindranath (void __user *)arg); 415089a36810SAnil Ravindranath break; 415189a36810SAnil Ravindranath 415289a36810SAnil Ravindranath default: 415389a36810SAnil Ravindranath retval = -ENOTTY; 415489a36810SAnil Ravindranath break; 415589a36810SAnil Ravindranath } 415689a36810SAnil Ravindranath 415789a36810SAnil Ravindranath kfree(hdr); 415889a36810SAnil Ravindranath 415989a36810SAnil Ravindranath return retval; 416089a36810SAnil Ravindranath } 416189a36810SAnil Ravindranath 416289a36810SAnil Ravindranath /** 416389a36810SAnil Ravindranath * File operations structure for management interface 416489a36810SAnil Ravindranath */ 416589a36810SAnil Ravindranath static const struct file_operations pmcraid_fops = { 416689a36810SAnil Ravindranath .owner = THIS_MODULE, 416789a36810SAnil Ravindranath .open = pmcraid_chr_open, 416889a36810SAnil Ravindranath .release = pmcraid_chr_release, 416989a36810SAnil Ravindranath .fasync = pmcraid_chr_fasync, 417089a36810SAnil Ravindranath .unlocked_ioctl = pmcraid_chr_ioctl, 417189a36810SAnil Ravindranath #ifdef CONFIG_COMPAT 417289a36810SAnil Ravindranath .compat_ioctl = pmcraid_chr_ioctl, 417389a36810SAnil Ravindranath #endif 41746038f373SArnd Bergmann .llseek = noop_llseek, 417589a36810SAnil Ravindranath }; 417689a36810SAnil Ravindranath 417789a36810SAnil Ravindranath 417889a36810SAnil Ravindranath 417989a36810SAnil Ravindranath 418089a36810SAnil Ravindranath /** 418189a36810SAnil Ravindranath * pmcraid_show_log_level - Display adapter's error logging level 418289a36810SAnil Ravindranath * @dev: class device struct 418389a36810SAnil Ravindranath * @buf: buffer 418489a36810SAnil Ravindranath * 418589a36810SAnil Ravindranath * Return value: 418689a36810SAnil Ravindranath * number of bytes printed to buffer 418789a36810SAnil Ravindranath */ 418889a36810SAnil Ravindranath static ssize_t pmcraid_show_log_level( 418989a36810SAnil Ravindranath struct device *dev, 419089a36810SAnil Ravindranath struct device_attribute *attr, 419189a36810SAnil Ravindranath char *buf) 419289a36810SAnil Ravindranath { 419389a36810SAnil Ravindranath struct Scsi_Host *shost = class_to_shost(dev); 419489a36810SAnil Ravindranath struct pmcraid_instance *pinstance = 419589a36810SAnil Ravindranath (struct pmcraid_instance *)shost->hostdata; 419689a36810SAnil Ravindranath return snprintf(buf, PAGE_SIZE, "%d\n", pinstance->current_log_level); 419789a36810SAnil Ravindranath } 419889a36810SAnil Ravindranath 419989a36810SAnil Ravindranath /** 420089a36810SAnil Ravindranath * pmcraid_store_log_level - Change the adapter's error logging level 420189a36810SAnil Ravindranath * @dev: class device struct 420289a36810SAnil Ravindranath * @buf: buffer 420389a36810SAnil Ravindranath * @count: not used 420489a36810SAnil Ravindranath * 420589a36810SAnil Ravindranath * Return value: 420689a36810SAnil Ravindranath * number of bytes printed to buffer 420789a36810SAnil Ravindranath */ 420889a36810SAnil Ravindranath static ssize_t pmcraid_store_log_level( 420989a36810SAnil Ravindranath struct device *dev, 421089a36810SAnil Ravindranath struct device_attribute *attr, 421189a36810SAnil Ravindranath const char *buf, 421289a36810SAnil Ravindranath size_t count 421389a36810SAnil Ravindranath ) 421489a36810SAnil Ravindranath { 421589a36810SAnil Ravindranath struct Scsi_Host *shost; 421689a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 421789a36810SAnil Ravindranath unsigned long val; 421889a36810SAnil Ravindranath 421989a36810SAnil Ravindranath if (strict_strtoul(buf, 10, &val)) 422089a36810SAnil Ravindranath return -EINVAL; 422189a36810SAnil Ravindranath /* log-level should be from 0 to 2 */ 422289a36810SAnil Ravindranath if (val > 2) 422389a36810SAnil Ravindranath return -EINVAL; 422489a36810SAnil Ravindranath 422589a36810SAnil Ravindranath shost = class_to_shost(dev); 422689a36810SAnil Ravindranath pinstance = (struct pmcraid_instance *)shost->hostdata; 422789a36810SAnil Ravindranath pinstance->current_log_level = val; 422889a36810SAnil Ravindranath 422989a36810SAnil Ravindranath return strlen(buf); 423089a36810SAnil Ravindranath } 423189a36810SAnil Ravindranath 423289a36810SAnil Ravindranath static struct device_attribute pmcraid_log_level_attr = { 423389a36810SAnil Ravindranath .attr = { 423489a36810SAnil Ravindranath .name = "log_level", 423589a36810SAnil Ravindranath .mode = S_IRUGO | S_IWUSR, 423689a36810SAnil Ravindranath }, 423789a36810SAnil Ravindranath .show = pmcraid_show_log_level, 423889a36810SAnil Ravindranath .store = pmcraid_store_log_level, 423989a36810SAnil Ravindranath }; 424089a36810SAnil Ravindranath 424189a36810SAnil Ravindranath /** 424289a36810SAnil Ravindranath * pmcraid_show_drv_version - Display driver version 424389a36810SAnil Ravindranath * @dev: class device struct 424489a36810SAnil Ravindranath * @buf: buffer 424589a36810SAnil Ravindranath * 424689a36810SAnil Ravindranath * Return value: 424789a36810SAnil Ravindranath * number of bytes printed to buffer 424889a36810SAnil Ravindranath */ 424989a36810SAnil Ravindranath static ssize_t pmcraid_show_drv_version( 425089a36810SAnil Ravindranath struct device *dev, 425189a36810SAnil Ravindranath struct device_attribute *attr, 425289a36810SAnil Ravindranath char *buf 425389a36810SAnil Ravindranath ) 425489a36810SAnil Ravindranath { 425589a36810SAnil Ravindranath return snprintf(buf, PAGE_SIZE, "version: %s, build date: %s\n", 425689a36810SAnil Ravindranath PMCRAID_DRIVER_VERSION, PMCRAID_DRIVER_DATE); 425789a36810SAnil Ravindranath } 425889a36810SAnil Ravindranath 425989a36810SAnil Ravindranath static struct device_attribute pmcraid_driver_version_attr = { 426089a36810SAnil Ravindranath .attr = { 426189a36810SAnil Ravindranath .name = "drv_version", 426289a36810SAnil Ravindranath .mode = S_IRUGO, 426389a36810SAnil Ravindranath }, 426489a36810SAnil Ravindranath .show = pmcraid_show_drv_version, 426589a36810SAnil Ravindranath }; 426689a36810SAnil Ravindranath 426789a36810SAnil Ravindranath /** 426889a36810SAnil Ravindranath * pmcraid_show_io_adapter_id - Display driver assigned adapter id 426989a36810SAnil Ravindranath * @dev: class device struct 427089a36810SAnil Ravindranath * @buf: buffer 427189a36810SAnil Ravindranath * 427289a36810SAnil Ravindranath * Return value: 427389a36810SAnil Ravindranath * number of bytes printed to buffer 427489a36810SAnil Ravindranath */ 427589a36810SAnil Ravindranath static ssize_t pmcraid_show_adapter_id( 427689a36810SAnil Ravindranath struct device *dev, 427789a36810SAnil Ravindranath struct device_attribute *attr, 427889a36810SAnil Ravindranath char *buf 427989a36810SAnil Ravindranath ) 428089a36810SAnil Ravindranath { 428189a36810SAnil Ravindranath struct Scsi_Host *shost = class_to_shost(dev); 428289a36810SAnil Ravindranath struct pmcraid_instance *pinstance = 428389a36810SAnil Ravindranath (struct pmcraid_instance *)shost->hostdata; 428489a36810SAnil Ravindranath u32 adapter_id = (pinstance->pdev->bus->number << 8) | 428589a36810SAnil Ravindranath pinstance->pdev->devfn; 428689a36810SAnil Ravindranath u32 aen_group = pmcraid_event_family.id; 428789a36810SAnil Ravindranath 428889a36810SAnil Ravindranath return snprintf(buf, PAGE_SIZE, 428989a36810SAnil Ravindranath "adapter id: %d\nminor: %d\naen group: %d\n", 429089a36810SAnil Ravindranath adapter_id, MINOR(pinstance->cdev.dev), aen_group); 429189a36810SAnil Ravindranath } 429289a36810SAnil Ravindranath 429389a36810SAnil Ravindranath static struct device_attribute pmcraid_adapter_id_attr = { 429489a36810SAnil Ravindranath .attr = { 429589a36810SAnil Ravindranath .name = "adapter_id", 429689a36810SAnil Ravindranath .mode = S_IRUGO | S_IWUSR, 429789a36810SAnil Ravindranath }, 429889a36810SAnil Ravindranath .show = pmcraid_show_adapter_id, 429989a36810SAnil Ravindranath }; 430089a36810SAnil Ravindranath 430189a36810SAnil Ravindranath static struct device_attribute *pmcraid_host_attrs[] = { 430289a36810SAnil Ravindranath &pmcraid_log_level_attr, 430389a36810SAnil Ravindranath &pmcraid_driver_version_attr, 430489a36810SAnil Ravindranath &pmcraid_adapter_id_attr, 430589a36810SAnil Ravindranath NULL, 430689a36810SAnil Ravindranath }; 430789a36810SAnil Ravindranath 430889a36810SAnil Ravindranath 430989a36810SAnil Ravindranath /* host template structure for pmcraid driver */ 431089a36810SAnil Ravindranath static struct scsi_host_template pmcraid_host_template = { 431189a36810SAnil Ravindranath .module = THIS_MODULE, 431289a36810SAnil Ravindranath .name = PMCRAID_DRIVER_NAME, 431389a36810SAnil Ravindranath .queuecommand = pmcraid_queuecommand, 431489a36810SAnil Ravindranath .eh_abort_handler = pmcraid_eh_abort_handler, 431589a36810SAnil Ravindranath .eh_bus_reset_handler = pmcraid_eh_bus_reset_handler, 431689a36810SAnil Ravindranath .eh_target_reset_handler = pmcraid_eh_target_reset_handler, 431789a36810SAnil Ravindranath .eh_device_reset_handler = pmcraid_eh_device_reset_handler, 431889a36810SAnil Ravindranath .eh_host_reset_handler = pmcraid_eh_host_reset_handler, 431989a36810SAnil Ravindranath 432089a36810SAnil Ravindranath .slave_alloc = pmcraid_slave_alloc, 432189a36810SAnil Ravindranath .slave_configure = pmcraid_slave_configure, 432289a36810SAnil Ravindranath .slave_destroy = pmcraid_slave_destroy, 432389a36810SAnil Ravindranath .change_queue_depth = pmcraid_change_queue_depth, 432489a36810SAnil Ravindranath .change_queue_type = pmcraid_change_queue_type, 432589a36810SAnil Ravindranath .can_queue = PMCRAID_MAX_IO_CMD, 432689a36810SAnil Ravindranath .this_id = -1, 432789a36810SAnil Ravindranath .sg_tablesize = PMCRAID_MAX_IOADLS, 432889a36810SAnil Ravindranath .max_sectors = PMCRAID_IOA_MAX_SECTORS, 432989a36810SAnil Ravindranath .cmd_per_lun = PMCRAID_MAX_CMD_PER_LUN, 433089a36810SAnil Ravindranath .use_clustering = ENABLE_CLUSTERING, 433189a36810SAnil Ravindranath .shost_attrs = pmcraid_host_attrs, 433289a36810SAnil Ravindranath .proc_name = PMCRAID_DRIVER_NAME 433389a36810SAnil Ravindranath }; 433489a36810SAnil Ravindranath 4335c20c4267SAnil Ravindranath /* 4336c20c4267SAnil Ravindranath * pmcraid_isr_msix - implements MSI-X interrupt handling routine 4337c20c4267SAnil Ravindranath * @irq: interrupt vector number 4338c20c4267SAnil Ravindranath * @dev_id: pointer hrrq_vector 433989a36810SAnil Ravindranath * 434089a36810SAnil Ravindranath * Return Value 4341c20c4267SAnil Ravindranath * IRQ_HANDLED if interrupt is handled or IRQ_NONE if ignored 434289a36810SAnil Ravindranath */ 434389a36810SAnil Ravindranath 4344c20c4267SAnil Ravindranath static irqreturn_t pmcraid_isr_msix(int irq, void *dev_id) 4345c20c4267SAnil Ravindranath { 4346c20c4267SAnil Ravindranath struct pmcraid_isr_param *hrrq_vector; 4347c20c4267SAnil Ravindranath struct pmcraid_instance *pinstance; 4348c20c4267SAnil Ravindranath unsigned long lock_flags; 4349c20c4267SAnil Ravindranath u32 intrs_val; 4350c20c4267SAnil Ravindranath int hrrq_id; 4351c20c4267SAnil Ravindranath 4352c20c4267SAnil Ravindranath hrrq_vector = (struct pmcraid_isr_param *)dev_id; 4353c20c4267SAnil Ravindranath hrrq_id = hrrq_vector->hrrq_id; 4354c20c4267SAnil Ravindranath pinstance = hrrq_vector->drv_inst; 4355c20c4267SAnil Ravindranath 4356c20c4267SAnil Ravindranath if (!hrrq_id) { 4357c20c4267SAnil Ravindranath /* Read the interrupt */ 4358c20c4267SAnil Ravindranath intrs_val = pmcraid_read_interrupts(pinstance); 4359c20c4267SAnil Ravindranath if (intrs_val && 4360c20c4267SAnil Ravindranath ((ioread32(pinstance->int_regs.host_ioa_interrupt_reg) 4361c20c4267SAnil Ravindranath & DOORBELL_INTR_MSIX_CLR) == 0)) { 4362c20c4267SAnil Ravindranath /* Any error interrupts including unit_check, 4363c20c4267SAnil Ravindranath * initiate IOA reset.In case of unit check indicate 4364c20c4267SAnil Ravindranath * to reset_sequence that IOA unit checked and prepare 4365c20c4267SAnil Ravindranath * for a dump during reset sequence 4366c20c4267SAnil Ravindranath */ 4367c20c4267SAnil Ravindranath if (intrs_val & PMCRAID_ERROR_INTERRUPTS) { 4368c20c4267SAnil Ravindranath if (intrs_val & INTRS_IOA_UNIT_CHECK) 4369c20c4267SAnil Ravindranath pinstance->ioa_unit_check = 1; 4370c20c4267SAnil Ravindranath 4371c20c4267SAnil Ravindranath pmcraid_err("ISR: error interrupts: %x \ 4372c20c4267SAnil Ravindranath initiating reset\n", intrs_val); 4373c20c4267SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, 4374c20c4267SAnil Ravindranath lock_flags); 4375c20c4267SAnil Ravindranath pmcraid_initiate_reset(pinstance); 4376c20c4267SAnil Ravindranath spin_unlock_irqrestore( 4377c20c4267SAnil Ravindranath pinstance->host->host_lock, 4378c20c4267SAnil Ravindranath lock_flags); 4379c20c4267SAnil Ravindranath } 4380c20c4267SAnil Ravindranath /* If interrupt was as part of the ioa initialization, 4381c20c4267SAnil Ravindranath * clear it. Delete the timer and wakeup the 4382c20c4267SAnil Ravindranath * reset engine to proceed with reset sequence 4383c20c4267SAnil Ravindranath */ 4384c20c4267SAnil Ravindranath if (intrs_val & INTRS_TRANSITION_TO_OPERATIONAL) 4385c20c4267SAnil Ravindranath pmcraid_clr_trans_op(pinstance); 4386c20c4267SAnil Ravindranath 4387c20c4267SAnil Ravindranath /* Clear the interrupt register by writing 4388c20c4267SAnil Ravindranath * to host to ioa doorbell. Once done 4389c20c4267SAnil Ravindranath * FW will clear the interrupt. 4390c20c4267SAnil Ravindranath */ 4391c20c4267SAnil Ravindranath iowrite32(DOORBELL_INTR_MSIX_CLR, 4392c20c4267SAnil Ravindranath pinstance->int_regs.host_ioa_interrupt_reg); 4393c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.host_ioa_interrupt_reg); 4394c20c4267SAnil Ravindranath 4395c20c4267SAnil Ravindranath 4396c20c4267SAnil Ravindranath } 4397c20c4267SAnil Ravindranath } 4398c20c4267SAnil Ravindranath 439989a36810SAnil Ravindranath tasklet_schedule(&(pinstance->isr_tasklet[hrrq_id])); 4400c20c4267SAnil Ravindranath 4401c20c4267SAnil Ravindranath return IRQ_HANDLED; 440289a36810SAnil Ravindranath } 440389a36810SAnil Ravindranath 440489a36810SAnil Ravindranath /** 4405c20c4267SAnil Ravindranath * pmcraid_isr - implements legacy interrupt handling routine 440689a36810SAnil Ravindranath * 440789a36810SAnil Ravindranath * @irq: interrupt vector number 440889a36810SAnil Ravindranath * @dev_id: pointer hrrq_vector 440989a36810SAnil Ravindranath * 441089a36810SAnil Ravindranath * Return Value 441189a36810SAnil Ravindranath * IRQ_HANDLED if interrupt is handled or IRQ_NONE if ignored 441289a36810SAnil Ravindranath */ 441389a36810SAnil Ravindranath static irqreturn_t pmcraid_isr(int irq, void *dev_id) 441489a36810SAnil Ravindranath { 441589a36810SAnil Ravindranath struct pmcraid_isr_param *hrrq_vector; 441689a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 441789a36810SAnil Ravindranath u32 intrs; 4418c20c4267SAnil Ravindranath unsigned long lock_flags; 4419c20c4267SAnil Ravindranath int hrrq_id = 0; 442089a36810SAnil Ravindranath 442189a36810SAnil Ravindranath /* In case of legacy interrupt mode where interrupts are shared across 442289a36810SAnil Ravindranath * isrs, it may be possible that the current interrupt is not from IOA 442389a36810SAnil Ravindranath */ 442489a36810SAnil Ravindranath if (!dev_id) { 442589a36810SAnil Ravindranath printk(KERN_INFO "%s(): NULL host pointer\n", __func__); 442689a36810SAnil Ravindranath return IRQ_NONE; 442789a36810SAnil Ravindranath } 442889a36810SAnil Ravindranath hrrq_vector = (struct pmcraid_isr_param *)dev_id; 442989a36810SAnil Ravindranath pinstance = hrrq_vector->drv_inst; 443089a36810SAnil Ravindranath 443189a36810SAnil Ravindranath intrs = pmcraid_read_interrupts(pinstance); 443289a36810SAnil Ravindranath 4433c20c4267SAnil Ravindranath if (unlikely((intrs & PMCRAID_PCI_INTERRUPTS) == 0)) 443489a36810SAnil Ravindranath return IRQ_NONE; 443589a36810SAnil Ravindranath 443689a36810SAnil Ravindranath /* Any error interrupts including unit_check, initiate IOA reset. 443789a36810SAnil Ravindranath * In case of unit check indicate to reset_sequence that IOA unit 443889a36810SAnil Ravindranath * checked and prepare for a dump during reset sequence 443989a36810SAnil Ravindranath */ 444089a36810SAnil Ravindranath if (intrs & PMCRAID_ERROR_INTERRUPTS) { 444189a36810SAnil Ravindranath 444289a36810SAnil Ravindranath if (intrs & INTRS_IOA_UNIT_CHECK) 444389a36810SAnil Ravindranath pinstance->ioa_unit_check = 1; 444489a36810SAnil Ravindranath 444589a36810SAnil Ravindranath iowrite32(intrs, 444689a36810SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_clr_reg); 444789a36810SAnil Ravindranath pmcraid_err("ISR: error interrupts: %x initiating reset\n", 444889a36810SAnil Ravindranath intrs); 4449c20c4267SAnil Ravindranath intrs = ioread32( 4450c20c4267SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_clr_reg); 4451c20c4267SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 445289a36810SAnil Ravindranath pmcraid_initiate_reset(pinstance); 445389a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 4454c20c4267SAnil Ravindranath } else { 4455c20c4267SAnil Ravindranath /* If interrupt was as part of the ioa initialization, 4456c20c4267SAnil Ravindranath * clear. Delete the timer and wakeup the 4457c20c4267SAnil Ravindranath * reset engine to proceed with reset sequence 4458c20c4267SAnil Ravindranath */ 4459c20c4267SAnil Ravindranath if (intrs & INTRS_TRANSITION_TO_OPERATIONAL) { 4460c20c4267SAnil Ravindranath pmcraid_clr_trans_op(pinstance); 4461c20c4267SAnil Ravindranath } else { 4462c20c4267SAnil Ravindranath iowrite32(intrs, 4463c20c4267SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_clr_reg); 4464c20c4267SAnil Ravindranath ioread32( 4465c20c4267SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_clr_reg); 4466c20c4267SAnil Ravindranath 4467c20c4267SAnil Ravindranath tasklet_schedule( 4468c20c4267SAnil Ravindranath &(pinstance->isr_tasklet[hrrq_id])); 4469c20c4267SAnil Ravindranath } 4470c20c4267SAnil Ravindranath } 447189a36810SAnil Ravindranath 447289a36810SAnil Ravindranath return IRQ_HANDLED; 447389a36810SAnil Ravindranath } 447489a36810SAnil Ravindranath 447589a36810SAnil Ravindranath 447689a36810SAnil Ravindranath /** 447789a36810SAnil Ravindranath * pmcraid_worker_function - worker thread function 447889a36810SAnil Ravindranath * 447989a36810SAnil Ravindranath * @workp: pointer to struct work queue 448089a36810SAnil Ravindranath * 448189a36810SAnil Ravindranath * Return Value 448289a36810SAnil Ravindranath * None 448389a36810SAnil Ravindranath */ 448489a36810SAnil Ravindranath 448589a36810SAnil Ravindranath static void pmcraid_worker_function(struct work_struct *workp) 448689a36810SAnil Ravindranath { 448789a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 448889a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 448989a36810SAnil Ravindranath struct pmcraid_resource_entry *temp; 449089a36810SAnil Ravindranath struct scsi_device *sdev; 449189a36810SAnil Ravindranath unsigned long lock_flags; 449289a36810SAnil Ravindranath unsigned long host_lock_flags; 4493c20c4267SAnil Ravindranath u16 fw_version; 449489a36810SAnil Ravindranath u8 bus, target, lun; 449589a36810SAnil Ravindranath 449689a36810SAnil Ravindranath pinstance = container_of(workp, struct pmcraid_instance, worker_q); 449789a36810SAnil Ravindranath /* add resources only after host is added into system */ 449889a36810SAnil Ravindranath if (!atomic_read(&pinstance->expose_resources)) 449989a36810SAnil Ravindranath return; 450089a36810SAnil Ravindranath 4501c20c4267SAnil Ravindranath fw_version = be16_to_cpu(pinstance->inq_data->fw_version); 4502c20c4267SAnil Ravindranath 450389a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->resource_lock, lock_flags); 450489a36810SAnil Ravindranath list_for_each_entry_safe(res, temp, &pinstance->used_res_q, queue) { 450589a36810SAnil Ravindranath 450689a36810SAnil Ravindranath if (res->change_detected == RES_CHANGE_DEL && res->scsi_dev) { 450789a36810SAnil Ravindranath sdev = res->scsi_dev; 450889a36810SAnil Ravindranath 450989a36810SAnil Ravindranath /* host_lock must be held before calling 451089a36810SAnil Ravindranath * scsi_device_get 451189a36810SAnil Ravindranath */ 451289a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, 451389a36810SAnil Ravindranath host_lock_flags); 451489a36810SAnil Ravindranath if (!scsi_device_get(sdev)) { 451589a36810SAnil Ravindranath spin_unlock_irqrestore( 451689a36810SAnil Ravindranath pinstance->host->host_lock, 451789a36810SAnil Ravindranath host_lock_flags); 451889a36810SAnil Ravindranath pmcraid_info("deleting %x from midlayer\n", 451989a36810SAnil Ravindranath res->cfg_entry.resource_address); 452089a36810SAnil Ravindranath list_move_tail(&res->queue, 452189a36810SAnil Ravindranath &pinstance->free_res_q); 452289a36810SAnil Ravindranath spin_unlock_irqrestore( 452389a36810SAnil Ravindranath &pinstance->resource_lock, 452489a36810SAnil Ravindranath lock_flags); 452589a36810SAnil Ravindranath scsi_remove_device(sdev); 452689a36810SAnil Ravindranath scsi_device_put(sdev); 452789a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->resource_lock, 452889a36810SAnil Ravindranath lock_flags); 452989a36810SAnil Ravindranath res->change_detected = 0; 453089a36810SAnil Ravindranath } else { 453189a36810SAnil Ravindranath spin_unlock_irqrestore( 453289a36810SAnil Ravindranath pinstance->host->host_lock, 453389a36810SAnil Ravindranath host_lock_flags); 453489a36810SAnil Ravindranath } 453589a36810SAnil Ravindranath } 453689a36810SAnil Ravindranath } 453789a36810SAnil Ravindranath 453889a36810SAnil Ravindranath list_for_each_entry(res, &pinstance->used_res_q, queue) { 453989a36810SAnil Ravindranath 454089a36810SAnil Ravindranath if (res->change_detected == RES_CHANGE_ADD) { 454189a36810SAnil Ravindranath 4542c20c4267SAnil Ravindranath if (!pmcraid_expose_resource(fw_version, 4543c20c4267SAnil Ravindranath &res->cfg_entry)) 454489a36810SAnil Ravindranath continue; 454589a36810SAnil Ravindranath 454689a36810SAnil Ravindranath if (RES_IS_VSET(res->cfg_entry)) { 454789a36810SAnil Ravindranath bus = PMCRAID_VSET_BUS_ID; 4548c20c4267SAnil Ravindranath if (fw_version <= PMCRAID_FW_VERSION_1) 454989a36810SAnil Ravindranath target = res->cfg_entry.unique_flags1; 4550c20c4267SAnil Ravindranath else 4551c20c4267SAnil Ravindranath target = res->cfg_entry.array_id & 0xFF; 455289a36810SAnil Ravindranath lun = PMCRAID_VSET_LUN_ID; 455389a36810SAnil Ravindranath } else { 455489a36810SAnil Ravindranath bus = PMCRAID_PHYS_BUS_ID; 455589a36810SAnil Ravindranath target = 455689a36810SAnil Ravindranath RES_TARGET( 455789a36810SAnil Ravindranath res->cfg_entry.resource_address); 455889a36810SAnil Ravindranath lun = RES_LUN(res->cfg_entry.resource_address); 455989a36810SAnil Ravindranath } 456089a36810SAnil Ravindranath 456189a36810SAnil Ravindranath res->change_detected = 0; 456289a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, 456389a36810SAnil Ravindranath lock_flags); 456489a36810SAnil Ravindranath scsi_add_device(pinstance->host, bus, target, lun); 456589a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->resource_lock, 456689a36810SAnil Ravindranath lock_flags); 456789a36810SAnil Ravindranath } 456889a36810SAnil Ravindranath } 456989a36810SAnil Ravindranath 457089a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); 457189a36810SAnil Ravindranath } 457289a36810SAnil Ravindranath 457389a36810SAnil Ravindranath /** 457489a36810SAnil Ravindranath * pmcraid_tasklet_function - Tasklet function 457589a36810SAnil Ravindranath * 457689a36810SAnil Ravindranath * @instance: pointer to msix param structure 457789a36810SAnil Ravindranath * 457889a36810SAnil Ravindranath * Return Value 457989a36810SAnil Ravindranath * None 458089a36810SAnil Ravindranath */ 4581c20c4267SAnil Ravindranath static void pmcraid_tasklet_function(unsigned long instance) 458289a36810SAnil Ravindranath { 458389a36810SAnil Ravindranath struct pmcraid_isr_param *hrrq_vector; 458489a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 458589a36810SAnil Ravindranath unsigned long hrrq_lock_flags; 458689a36810SAnil Ravindranath unsigned long pending_lock_flags; 458789a36810SAnil Ravindranath unsigned long host_lock_flags; 458889a36810SAnil Ravindranath spinlock_t *lockp; /* hrrq buffer lock */ 458989a36810SAnil Ravindranath int id; 459089a36810SAnil Ravindranath __le32 resp; 459189a36810SAnil Ravindranath 459289a36810SAnil Ravindranath hrrq_vector = (struct pmcraid_isr_param *)instance; 459389a36810SAnil Ravindranath pinstance = hrrq_vector->drv_inst; 459489a36810SAnil Ravindranath id = hrrq_vector->hrrq_id; 459589a36810SAnil Ravindranath lockp = &(pinstance->hrrq_lock[id]); 459689a36810SAnil Ravindranath 459789a36810SAnil Ravindranath /* loop through each of the commands responded by IOA. Each HRRQ buf is 459889a36810SAnil Ravindranath * protected by its own lock. Traversals must be done within this lock 459989a36810SAnil Ravindranath * as there may be multiple tasklets running on multiple CPUs. Note 460089a36810SAnil Ravindranath * that the lock is held just for picking up the response handle and 460189a36810SAnil Ravindranath * manipulating hrrq_curr/toggle_bit values. 460289a36810SAnil Ravindranath */ 460389a36810SAnil Ravindranath spin_lock_irqsave(lockp, hrrq_lock_flags); 460489a36810SAnil Ravindranath 460589a36810SAnil Ravindranath resp = le32_to_cpu(*(pinstance->hrrq_curr[id])); 460689a36810SAnil Ravindranath 460789a36810SAnil Ravindranath while ((resp & HRRQ_TOGGLE_BIT) == 460889a36810SAnil Ravindranath pinstance->host_toggle_bit[id]) { 460989a36810SAnil Ravindranath 461089a36810SAnil Ravindranath int cmd_index = resp >> 2; 461189a36810SAnil Ravindranath struct pmcraid_cmd *cmd = NULL; 461289a36810SAnil Ravindranath 461389a36810SAnil Ravindranath if (pinstance->hrrq_curr[id] < pinstance->hrrq_end[id]) { 461489a36810SAnil Ravindranath pinstance->hrrq_curr[id]++; 461589a36810SAnil Ravindranath } else { 461689a36810SAnil Ravindranath pinstance->hrrq_curr[id] = pinstance->hrrq_start[id]; 461789a36810SAnil Ravindranath pinstance->host_toggle_bit[id] ^= 1u; 461889a36810SAnil Ravindranath } 461989a36810SAnil Ravindranath 4620c20c4267SAnil Ravindranath if (cmd_index >= PMCRAID_MAX_CMD) { 4621c20c4267SAnil Ravindranath /* In case of invalid response handle, log message */ 4622c20c4267SAnil Ravindranath pmcraid_err("Invalid response handle %d\n", cmd_index); 4623c20c4267SAnil Ravindranath resp = le32_to_cpu(*(pinstance->hrrq_curr[id])); 4624c20c4267SAnil Ravindranath continue; 4625c20c4267SAnil Ravindranath } 4626c20c4267SAnil Ravindranath 4627c20c4267SAnil Ravindranath cmd = pinstance->cmd_list[cmd_index]; 462889a36810SAnil Ravindranath spin_unlock_irqrestore(lockp, hrrq_lock_flags); 462989a36810SAnil Ravindranath 463089a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->pending_pool_lock, 463189a36810SAnil Ravindranath pending_lock_flags); 463289a36810SAnil Ravindranath list_del(&cmd->free_list); 463389a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->pending_pool_lock, 463489a36810SAnil Ravindranath pending_lock_flags); 463589a36810SAnil Ravindranath del_timer(&cmd->timer); 463689a36810SAnil Ravindranath atomic_dec(&pinstance->outstanding_cmds); 463789a36810SAnil Ravindranath 463889a36810SAnil Ravindranath if (cmd->cmd_done == pmcraid_ioa_reset) { 463989a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, 464089a36810SAnil Ravindranath host_lock_flags); 464189a36810SAnil Ravindranath cmd->cmd_done(cmd); 464289a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 464389a36810SAnil Ravindranath host_lock_flags); 464489a36810SAnil Ravindranath } else if (cmd->cmd_done != NULL) { 464589a36810SAnil Ravindranath cmd->cmd_done(cmd); 464689a36810SAnil Ravindranath } 464789a36810SAnil Ravindranath /* loop over until we are done with all responses */ 464889a36810SAnil Ravindranath spin_lock_irqsave(lockp, hrrq_lock_flags); 464989a36810SAnil Ravindranath resp = le32_to_cpu(*(pinstance->hrrq_curr[id])); 465089a36810SAnil Ravindranath } 465189a36810SAnil Ravindranath 465289a36810SAnil Ravindranath spin_unlock_irqrestore(lockp, hrrq_lock_flags); 465389a36810SAnil Ravindranath } 465489a36810SAnil Ravindranath 465589a36810SAnil Ravindranath /** 465689a36810SAnil Ravindranath * pmcraid_unregister_interrupt_handler - de-register interrupts handlers 465789a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 465889a36810SAnil Ravindranath * 465989a36810SAnil Ravindranath * This routine un-registers registered interrupt handler and 466089a36810SAnil Ravindranath * also frees irqs/vectors. 466189a36810SAnil Ravindranath * 466289a36810SAnil Ravindranath * Retun Value 466389a36810SAnil Ravindranath * None 466489a36810SAnil Ravindranath */ 466589a36810SAnil Ravindranath static 466689a36810SAnil Ravindranath void pmcraid_unregister_interrupt_handler(struct pmcraid_instance *pinstance) 466789a36810SAnil Ravindranath { 4668c20c4267SAnil Ravindranath int i; 4669c20c4267SAnil Ravindranath 4670c20c4267SAnil Ravindranath for (i = 0; i < pinstance->num_hrrq; i++) 4671c20c4267SAnil Ravindranath free_irq(pinstance->hrrq_vector[i].vector, 4672c20c4267SAnil Ravindranath &(pinstance->hrrq_vector[i])); 4673c20c4267SAnil Ravindranath 4674c20c4267SAnil Ravindranath if (pinstance->interrupt_mode) { 4675c20c4267SAnil Ravindranath pci_disable_msix(pinstance->pdev); 4676c20c4267SAnil Ravindranath pinstance->interrupt_mode = 0; 4677c20c4267SAnil Ravindranath } 467889a36810SAnil Ravindranath } 467989a36810SAnil Ravindranath 468089a36810SAnil Ravindranath /** 468189a36810SAnil Ravindranath * pmcraid_register_interrupt_handler - registers interrupt handler 468289a36810SAnil Ravindranath * @pinstance: pointer to per-adapter instance structure 468389a36810SAnil Ravindranath * 468489a36810SAnil Ravindranath * Return Value 468589a36810SAnil Ravindranath * 0 on success, non-zero error code otherwise. 468689a36810SAnil Ravindranath */ 468789a36810SAnil Ravindranath static int 468889a36810SAnil Ravindranath pmcraid_register_interrupt_handler(struct pmcraid_instance *pinstance) 468989a36810SAnil Ravindranath { 4690c20c4267SAnil Ravindranath int rc; 469189a36810SAnil Ravindranath struct pci_dev *pdev = pinstance->pdev; 469289a36810SAnil Ravindranath 46935da61410SAnil Ravindranath if ((pmcraid_enable_msix) && 46945da61410SAnil Ravindranath (pci_find_capability(pdev, PCI_CAP_ID_MSIX))) { 4695c20c4267SAnil Ravindranath int num_hrrq = PMCRAID_NUM_MSIX_VECTORS; 4696c20c4267SAnil Ravindranath struct msix_entry entries[PMCRAID_NUM_MSIX_VECTORS]; 4697c20c4267SAnil Ravindranath int i; 4698c20c4267SAnil Ravindranath for (i = 0; i < PMCRAID_NUM_MSIX_VECTORS; i++) 4699c20c4267SAnil Ravindranath entries[i].entry = i; 4700c20c4267SAnil Ravindranath 4701c20c4267SAnil Ravindranath rc = pci_enable_msix(pdev, entries, num_hrrq); 4702c20c4267SAnil Ravindranath if (rc < 0) 4703c20c4267SAnil Ravindranath goto pmcraid_isr_legacy; 4704c20c4267SAnil Ravindranath 4705c20c4267SAnil Ravindranath /* Check how many MSIX vectors are allocated and register 4706c20c4267SAnil Ravindranath * msi-x handlers for each of them giving appropriate buffer 4707c20c4267SAnil Ravindranath */ 4708c20c4267SAnil Ravindranath if (rc > 0) { 4709c20c4267SAnil Ravindranath num_hrrq = rc; 4710c20c4267SAnil Ravindranath if (pci_enable_msix(pdev, entries, num_hrrq)) 4711c20c4267SAnil Ravindranath goto pmcraid_isr_legacy; 4712c20c4267SAnil Ravindranath } 4713c20c4267SAnil Ravindranath 4714c20c4267SAnil Ravindranath for (i = 0; i < num_hrrq; i++) { 4715c20c4267SAnil Ravindranath pinstance->hrrq_vector[i].hrrq_id = i; 4716c20c4267SAnil Ravindranath pinstance->hrrq_vector[i].drv_inst = pinstance; 4717c20c4267SAnil Ravindranath pinstance->hrrq_vector[i].vector = entries[i].vector; 4718c20c4267SAnil Ravindranath rc = request_irq(pinstance->hrrq_vector[i].vector, 4719c20c4267SAnil Ravindranath pmcraid_isr_msix, 0, 4720c20c4267SAnil Ravindranath PMCRAID_DRIVER_NAME, 4721c20c4267SAnil Ravindranath &(pinstance->hrrq_vector[i])); 4722c20c4267SAnil Ravindranath 4723c20c4267SAnil Ravindranath if (rc) { 4724c20c4267SAnil Ravindranath int j; 4725c20c4267SAnil Ravindranath for (j = 0; j < i; j++) 4726c20c4267SAnil Ravindranath free_irq(entries[j].vector, 4727c20c4267SAnil Ravindranath &(pinstance->hrrq_vector[j])); 4728c20c4267SAnil Ravindranath pci_disable_msix(pdev); 4729c20c4267SAnil Ravindranath goto pmcraid_isr_legacy; 4730c20c4267SAnil Ravindranath } 4731c20c4267SAnil Ravindranath } 4732c20c4267SAnil Ravindranath 4733c20c4267SAnil Ravindranath pinstance->num_hrrq = num_hrrq; 4734c20c4267SAnil Ravindranath pinstance->interrupt_mode = 1; 4735c20c4267SAnil Ravindranath iowrite32(DOORBELL_INTR_MODE_MSIX, 4736c20c4267SAnil Ravindranath pinstance->int_regs.host_ioa_interrupt_reg); 4737c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.host_ioa_interrupt_reg); 4738c20c4267SAnil Ravindranath goto pmcraid_isr_out; 4739c20c4267SAnil Ravindranath } 4740c20c4267SAnil Ravindranath 4741c20c4267SAnil Ravindranath pmcraid_isr_legacy: 4742c20c4267SAnil Ravindranath /* If MSI-X registration failed fallback to legacy mode, where 4743c20c4267SAnil Ravindranath * only one hrrq entry will be used 4744c20c4267SAnil Ravindranath */ 474589a36810SAnil Ravindranath pinstance->hrrq_vector[0].hrrq_id = 0; 474689a36810SAnil Ravindranath pinstance->hrrq_vector[0].drv_inst = pinstance; 4747c20c4267SAnil Ravindranath pinstance->hrrq_vector[0].vector = pdev->irq; 474889a36810SAnil Ravindranath pinstance->num_hrrq = 1; 4749c20c4267SAnil Ravindranath rc = 0; 4750c20c4267SAnil Ravindranath 4751c20c4267SAnil Ravindranath rc = request_irq(pdev->irq, pmcraid_isr, IRQF_SHARED, 475289a36810SAnil Ravindranath PMCRAID_DRIVER_NAME, &pinstance->hrrq_vector[0]); 4753c20c4267SAnil Ravindranath pmcraid_isr_out: 4754c20c4267SAnil Ravindranath return rc; 475589a36810SAnil Ravindranath } 475689a36810SAnil Ravindranath 475789a36810SAnil Ravindranath /** 475889a36810SAnil Ravindranath * pmcraid_release_cmd_blocks - release buufers allocated for command blocks 475989a36810SAnil Ravindranath * @pinstance: per adapter instance structure pointer 476089a36810SAnil Ravindranath * @max_index: number of buffer blocks to release 476189a36810SAnil Ravindranath * 476289a36810SAnil Ravindranath * Return Value 476389a36810SAnil Ravindranath * None 476489a36810SAnil Ravindranath */ 476589a36810SAnil Ravindranath static void 476689a36810SAnil Ravindranath pmcraid_release_cmd_blocks(struct pmcraid_instance *pinstance, int max_index) 476789a36810SAnil Ravindranath { 476889a36810SAnil Ravindranath int i; 476989a36810SAnil Ravindranath for (i = 0; i < max_index; i++) { 477089a36810SAnil Ravindranath kmem_cache_free(pinstance->cmd_cachep, pinstance->cmd_list[i]); 477189a36810SAnil Ravindranath pinstance->cmd_list[i] = NULL; 477289a36810SAnil Ravindranath } 477389a36810SAnil Ravindranath kmem_cache_destroy(pinstance->cmd_cachep); 477489a36810SAnil Ravindranath pinstance->cmd_cachep = NULL; 477589a36810SAnil Ravindranath } 477689a36810SAnil Ravindranath 477789a36810SAnil Ravindranath /** 477889a36810SAnil Ravindranath * pmcraid_release_control_blocks - releases buffers alloced for control blocks 477989a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 478089a36810SAnil Ravindranath * @max_index: number of buffers (from 0 onwards) to release 478189a36810SAnil Ravindranath * 478289a36810SAnil Ravindranath * This function assumes that the command blocks for which control blocks are 478389a36810SAnil Ravindranath * linked are not released. 478489a36810SAnil Ravindranath * 478589a36810SAnil Ravindranath * Return Value 478689a36810SAnil Ravindranath * None 478789a36810SAnil Ravindranath */ 478889a36810SAnil Ravindranath static void 478989a36810SAnil Ravindranath pmcraid_release_control_blocks( 479089a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 479189a36810SAnil Ravindranath int max_index 479289a36810SAnil Ravindranath ) 479389a36810SAnil Ravindranath { 479489a36810SAnil Ravindranath int i; 479589a36810SAnil Ravindranath 479689a36810SAnil Ravindranath if (pinstance->control_pool == NULL) 479789a36810SAnil Ravindranath return; 479889a36810SAnil Ravindranath 479989a36810SAnil Ravindranath for (i = 0; i < max_index; i++) { 480089a36810SAnil Ravindranath pci_pool_free(pinstance->control_pool, 480189a36810SAnil Ravindranath pinstance->cmd_list[i]->ioa_cb, 480289a36810SAnil Ravindranath pinstance->cmd_list[i]->ioa_cb_bus_addr); 480389a36810SAnil Ravindranath pinstance->cmd_list[i]->ioa_cb = NULL; 480489a36810SAnil Ravindranath pinstance->cmd_list[i]->ioa_cb_bus_addr = 0; 480589a36810SAnil Ravindranath } 480689a36810SAnil Ravindranath pci_pool_destroy(pinstance->control_pool); 480789a36810SAnil Ravindranath pinstance->control_pool = NULL; 480889a36810SAnil Ravindranath } 480989a36810SAnil Ravindranath 481089a36810SAnil Ravindranath /** 481189a36810SAnil Ravindranath * pmcraid_allocate_cmd_blocks - allocate memory for cmd block structures 481289a36810SAnil Ravindranath * @pinstance - pointer to per adapter instance structure 481389a36810SAnil Ravindranath * 481489a36810SAnil Ravindranath * Allocates memory for command blocks using kernel slab allocator. 481589a36810SAnil Ravindranath * 481689a36810SAnil Ravindranath * Return Value 481789a36810SAnil Ravindranath * 0 in case of success; -ENOMEM in case of failure 481889a36810SAnil Ravindranath */ 481989a36810SAnil Ravindranath static int __devinit 482089a36810SAnil Ravindranath pmcraid_allocate_cmd_blocks(struct pmcraid_instance *pinstance) 482189a36810SAnil Ravindranath { 482289a36810SAnil Ravindranath int i; 482389a36810SAnil Ravindranath 482489a36810SAnil Ravindranath sprintf(pinstance->cmd_pool_name, "pmcraid_cmd_pool_%d", 482589a36810SAnil Ravindranath pinstance->host->unique_id); 482689a36810SAnil Ravindranath 482789a36810SAnil Ravindranath 482889a36810SAnil Ravindranath pinstance->cmd_cachep = kmem_cache_create( 482989a36810SAnil Ravindranath pinstance->cmd_pool_name, 483089a36810SAnil Ravindranath sizeof(struct pmcraid_cmd), 0, 483189a36810SAnil Ravindranath SLAB_HWCACHE_ALIGN, NULL); 483289a36810SAnil Ravindranath if (!pinstance->cmd_cachep) 483389a36810SAnil Ravindranath return -ENOMEM; 483489a36810SAnil Ravindranath 483589a36810SAnil Ravindranath for (i = 0; i < PMCRAID_MAX_CMD; i++) { 483689a36810SAnil Ravindranath pinstance->cmd_list[i] = 483789a36810SAnil Ravindranath kmem_cache_alloc(pinstance->cmd_cachep, GFP_KERNEL); 483889a36810SAnil Ravindranath if (!pinstance->cmd_list[i]) { 483989a36810SAnil Ravindranath pmcraid_release_cmd_blocks(pinstance, i); 484089a36810SAnil Ravindranath return -ENOMEM; 484189a36810SAnil Ravindranath } 484289a36810SAnil Ravindranath } 484389a36810SAnil Ravindranath return 0; 484489a36810SAnil Ravindranath } 484589a36810SAnil Ravindranath 484689a36810SAnil Ravindranath /** 484789a36810SAnil Ravindranath * pmcraid_allocate_control_blocks - allocates memory control blocks 484889a36810SAnil Ravindranath * @pinstance : pointer to per adapter instance structure 484989a36810SAnil Ravindranath * 485089a36810SAnil Ravindranath * This function allocates PCI memory for DMAable buffers like IOARCB, IOADLs 485189a36810SAnil Ravindranath * and IOASAs. This is called after command blocks are already allocated. 485289a36810SAnil Ravindranath * 485389a36810SAnil Ravindranath * Return Value 485489a36810SAnil Ravindranath * 0 in case it can allocate all control blocks, otherwise -ENOMEM 485589a36810SAnil Ravindranath */ 485689a36810SAnil Ravindranath static int __devinit 485789a36810SAnil Ravindranath pmcraid_allocate_control_blocks(struct pmcraid_instance *pinstance) 485889a36810SAnil Ravindranath { 485989a36810SAnil Ravindranath int i; 486089a36810SAnil Ravindranath 486189a36810SAnil Ravindranath sprintf(pinstance->ctl_pool_name, "pmcraid_control_pool_%d", 486289a36810SAnil Ravindranath pinstance->host->unique_id); 486389a36810SAnil Ravindranath 486489a36810SAnil Ravindranath pinstance->control_pool = 486589a36810SAnil Ravindranath pci_pool_create(pinstance->ctl_pool_name, 486689a36810SAnil Ravindranath pinstance->pdev, 486789a36810SAnil Ravindranath sizeof(struct pmcraid_control_block), 486889a36810SAnil Ravindranath PMCRAID_IOARCB_ALIGNMENT, 0); 486989a36810SAnil Ravindranath 487089a36810SAnil Ravindranath if (!pinstance->control_pool) 487189a36810SAnil Ravindranath return -ENOMEM; 487289a36810SAnil Ravindranath 487389a36810SAnil Ravindranath for (i = 0; i < PMCRAID_MAX_CMD; i++) { 487489a36810SAnil Ravindranath pinstance->cmd_list[i]->ioa_cb = 487589a36810SAnil Ravindranath pci_pool_alloc( 487689a36810SAnil Ravindranath pinstance->control_pool, 487789a36810SAnil Ravindranath GFP_KERNEL, 487889a36810SAnil Ravindranath &(pinstance->cmd_list[i]->ioa_cb_bus_addr)); 487989a36810SAnil Ravindranath 488089a36810SAnil Ravindranath if (!pinstance->cmd_list[i]->ioa_cb) { 488189a36810SAnil Ravindranath pmcraid_release_control_blocks(pinstance, i); 488289a36810SAnil Ravindranath return -ENOMEM; 488389a36810SAnil Ravindranath } 488489a36810SAnil Ravindranath memset(pinstance->cmd_list[i]->ioa_cb, 0, 488589a36810SAnil Ravindranath sizeof(struct pmcraid_control_block)); 488689a36810SAnil Ravindranath } 488789a36810SAnil Ravindranath return 0; 488889a36810SAnil Ravindranath } 488989a36810SAnil Ravindranath 489089a36810SAnil Ravindranath /** 489189a36810SAnil Ravindranath * pmcraid_release_host_rrqs - release memory allocated for hrrq buffer(s) 489289a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 489389a36810SAnil Ravindranath * @maxindex: size of hrrq buffer pointer array 489489a36810SAnil Ravindranath * 489589a36810SAnil Ravindranath * Return Value 489689a36810SAnil Ravindranath * None 489789a36810SAnil Ravindranath */ 489889a36810SAnil Ravindranath static void 489989a36810SAnil Ravindranath pmcraid_release_host_rrqs(struct pmcraid_instance *pinstance, int maxindex) 490089a36810SAnil Ravindranath { 490189a36810SAnil Ravindranath int i; 490289a36810SAnil Ravindranath for (i = 0; i < maxindex; i++) { 490389a36810SAnil Ravindranath 490489a36810SAnil Ravindranath pci_free_consistent(pinstance->pdev, 490589a36810SAnil Ravindranath HRRQ_ENTRY_SIZE * PMCRAID_MAX_CMD, 490689a36810SAnil Ravindranath pinstance->hrrq_start[i], 490789a36810SAnil Ravindranath pinstance->hrrq_start_bus_addr[i]); 490889a36810SAnil Ravindranath 490989a36810SAnil Ravindranath /* reset pointers and toggle bit to zeros */ 491089a36810SAnil Ravindranath pinstance->hrrq_start[i] = NULL; 491189a36810SAnil Ravindranath pinstance->hrrq_start_bus_addr[i] = 0; 491289a36810SAnil Ravindranath pinstance->host_toggle_bit[i] = 0; 491389a36810SAnil Ravindranath } 491489a36810SAnil Ravindranath } 491589a36810SAnil Ravindranath 491689a36810SAnil Ravindranath /** 491789a36810SAnil Ravindranath * pmcraid_allocate_host_rrqs - Allocate and initialize host RRQ buffers 491889a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 491989a36810SAnil Ravindranath * 492089a36810SAnil Ravindranath * Return value 492189a36810SAnil Ravindranath * 0 hrrq buffers are allocated, -ENOMEM otherwise. 492289a36810SAnil Ravindranath */ 492389a36810SAnil Ravindranath static int __devinit 492489a36810SAnil Ravindranath pmcraid_allocate_host_rrqs(struct pmcraid_instance *pinstance) 492589a36810SAnil Ravindranath { 4926c20c4267SAnil Ravindranath int i, buffer_size; 4927c20c4267SAnil Ravindranath 4928c20c4267SAnil Ravindranath buffer_size = HRRQ_ENTRY_SIZE * PMCRAID_MAX_CMD; 492989a36810SAnil Ravindranath 493089a36810SAnil Ravindranath for (i = 0; i < pinstance->num_hrrq; i++) { 493189a36810SAnil Ravindranath pinstance->hrrq_start[i] = 493289a36810SAnil Ravindranath pci_alloc_consistent( 493389a36810SAnil Ravindranath pinstance->pdev, 493489a36810SAnil Ravindranath buffer_size, 493589a36810SAnil Ravindranath &(pinstance->hrrq_start_bus_addr[i])); 493689a36810SAnil Ravindranath 493789a36810SAnil Ravindranath if (pinstance->hrrq_start[i] == 0) { 4938c20c4267SAnil Ravindranath pmcraid_err("pci_alloc failed for hrrq vector : %d\n", 4939c20c4267SAnil Ravindranath i); 494089a36810SAnil Ravindranath pmcraid_release_host_rrqs(pinstance, i); 494189a36810SAnil Ravindranath return -ENOMEM; 494289a36810SAnil Ravindranath } 494389a36810SAnil Ravindranath 494489a36810SAnil Ravindranath memset(pinstance->hrrq_start[i], 0, buffer_size); 494589a36810SAnil Ravindranath pinstance->hrrq_curr[i] = pinstance->hrrq_start[i]; 494689a36810SAnil Ravindranath pinstance->hrrq_end[i] = 4947c20c4267SAnil Ravindranath pinstance->hrrq_start[i] + PMCRAID_MAX_CMD - 1; 494889a36810SAnil Ravindranath pinstance->host_toggle_bit[i] = 1; 494989a36810SAnil Ravindranath spin_lock_init(&pinstance->hrrq_lock[i]); 495089a36810SAnil Ravindranath } 495189a36810SAnil Ravindranath return 0; 495289a36810SAnil Ravindranath } 495389a36810SAnil Ravindranath 495489a36810SAnil Ravindranath /** 495589a36810SAnil Ravindranath * pmcraid_release_hcams - release HCAM buffers 495689a36810SAnil Ravindranath * 495789a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 495889a36810SAnil Ravindranath * 495989a36810SAnil Ravindranath * Return value 496089a36810SAnil Ravindranath * none 496189a36810SAnil Ravindranath */ 496289a36810SAnil Ravindranath static void pmcraid_release_hcams(struct pmcraid_instance *pinstance) 496389a36810SAnil Ravindranath { 496489a36810SAnil Ravindranath if (pinstance->ccn.msg != NULL) { 496589a36810SAnil Ravindranath pci_free_consistent(pinstance->pdev, 496689a36810SAnil Ravindranath PMCRAID_AEN_HDR_SIZE + 4967c20c4267SAnil Ravindranath sizeof(struct pmcraid_hcam_ccn_ext), 496889a36810SAnil Ravindranath pinstance->ccn.msg, 496989a36810SAnil Ravindranath pinstance->ccn.baddr); 497089a36810SAnil Ravindranath 497189a36810SAnil Ravindranath pinstance->ccn.msg = NULL; 497289a36810SAnil Ravindranath pinstance->ccn.hcam = NULL; 497389a36810SAnil Ravindranath pinstance->ccn.baddr = 0; 497489a36810SAnil Ravindranath } 497589a36810SAnil Ravindranath 497689a36810SAnil Ravindranath if (pinstance->ldn.msg != NULL) { 497789a36810SAnil Ravindranath pci_free_consistent(pinstance->pdev, 497889a36810SAnil Ravindranath PMCRAID_AEN_HDR_SIZE + 497989a36810SAnil Ravindranath sizeof(struct pmcraid_hcam_ldn), 498089a36810SAnil Ravindranath pinstance->ldn.msg, 498189a36810SAnil Ravindranath pinstance->ldn.baddr); 498289a36810SAnil Ravindranath 498389a36810SAnil Ravindranath pinstance->ldn.msg = NULL; 498489a36810SAnil Ravindranath pinstance->ldn.hcam = NULL; 498589a36810SAnil Ravindranath pinstance->ldn.baddr = 0; 498689a36810SAnil Ravindranath } 498789a36810SAnil Ravindranath } 498889a36810SAnil Ravindranath 498989a36810SAnil Ravindranath /** 499089a36810SAnil Ravindranath * pmcraid_allocate_hcams - allocates HCAM buffers 499189a36810SAnil Ravindranath * @pinstance : pointer to per adapter instance structure 499289a36810SAnil Ravindranath * 499389a36810SAnil Ravindranath * Return Value: 499489a36810SAnil Ravindranath * 0 in case of successful allocation, non-zero otherwise 499589a36810SAnil Ravindranath */ 499689a36810SAnil Ravindranath static int pmcraid_allocate_hcams(struct pmcraid_instance *pinstance) 499789a36810SAnil Ravindranath { 499889a36810SAnil Ravindranath pinstance->ccn.msg = pci_alloc_consistent( 499989a36810SAnil Ravindranath pinstance->pdev, 500089a36810SAnil Ravindranath PMCRAID_AEN_HDR_SIZE + 5001c20c4267SAnil Ravindranath sizeof(struct pmcraid_hcam_ccn_ext), 500289a36810SAnil Ravindranath &(pinstance->ccn.baddr)); 500389a36810SAnil Ravindranath 500489a36810SAnil Ravindranath pinstance->ldn.msg = pci_alloc_consistent( 500589a36810SAnil Ravindranath pinstance->pdev, 500689a36810SAnil Ravindranath PMCRAID_AEN_HDR_SIZE + 500789a36810SAnil Ravindranath sizeof(struct pmcraid_hcam_ldn), 500889a36810SAnil Ravindranath &(pinstance->ldn.baddr)); 500989a36810SAnil Ravindranath 501089a36810SAnil Ravindranath if (pinstance->ldn.msg == NULL || pinstance->ccn.msg == NULL) { 501189a36810SAnil Ravindranath pmcraid_release_hcams(pinstance); 501289a36810SAnil Ravindranath } else { 501389a36810SAnil Ravindranath pinstance->ccn.hcam = 501489a36810SAnil Ravindranath (void *)pinstance->ccn.msg + PMCRAID_AEN_HDR_SIZE; 501589a36810SAnil Ravindranath pinstance->ldn.hcam = 501689a36810SAnil Ravindranath (void *)pinstance->ldn.msg + PMCRAID_AEN_HDR_SIZE; 501789a36810SAnil Ravindranath 501889a36810SAnil Ravindranath atomic_set(&pinstance->ccn.ignore, 0); 501989a36810SAnil Ravindranath atomic_set(&pinstance->ldn.ignore, 0); 502089a36810SAnil Ravindranath } 502189a36810SAnil Ravindranath 502289a36810SAnil Ravindranath return (pinstance->ldn.msg == NULL) ? -ENOMEM : 0; 502389a36810SAnil Ravindranath } 502489a36810SAnil Ravindranath 502589a36810SAnil Ravindranath /** 502689a36810SAnil Ravindranath * pmcraid_release_config_buffers - release config.table buffers 502789a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 502889a36810SAnil Ravindranath * 502989a36810SAnil Ravindranath * Return Value 503089a36810SAnil Ravindranath * none 503189a36810SAnil Ravindranath */ 503289a36810SAnil Ravindranath static void pmcraid_release_config_buffers(struct pmcraid_instance *pinstance) 503389a36810SAnil Ravindranath { 503489a36810SAnil Ravindranath if (pinstance->cfg_table != NULL && 503589a36810SAnil Ravindranath pinstance->cfg_table_bus_addr != 0) { 503689a36810SAnil Ravindranath pci_free_consistent(pinstance->pdev, 503789a36810SAnil Ravindranath sizeof(struct pmcraid_config_table), 503889a36810SAnil Ravindranath pinstance->cfg_table, 503989a36810SAnil Ravindranath pinstance->cfg_table_bus_addr); 504089a36810SAnil Ravindranath pinstance->cfg_table = NULL; 504189a36810SAnil Ravindranath pinstance->cfg_table_bus_addr = 0; 504289a36810SAnil Ravindranath } 504389a36810SAnil Ravindranath 504489a36810SAnil Ravindranath if (pinstance->res_entries != NULL) { 504589a36810SAnil Ravindranath int i; 504689a36810SAnil Ravindranath 504789a36810SAnil Ravindranath for (i = 0; i < PMCRAID_MAX_RESOURCES; i++) 504889a36810SAnil Ravindranath list_del(&pinstance->res_entries[i].queue); 504989a36810SAnil Ravindranath kfree(pinstance->res_entries); 505089a36810SAnil Ravindranath pinstance->res_entries = NULL; 505189a36810SAnil Ravindranath } 505289a36810SAnil Ravindranath 505389a36810SAnil Ravindranath pmcraid_release_hcams(pinstance); 505489a36810SAnil Ravindranath } 505589a36810SAnil Ravindranath 505689a36810SAnil Ravindranath /** 505789a36810SAnil Ravindranath * pmcraid_allocate_config_buffers - allocates DMAable memory for config table 505889a36810SAnil Ravindranath * @pinstance : pointer to per adapter instance structure 505989a36810SAnil Ravindranath * 506089a36810SAnil Ravindranath * Return Value 506189a36810SAnil Ravindranath * 0 for successful allocation, -ENOMEM for any failure 506289a36810SAnil Ravindranath */ 506389a36810SAnil Ravindranath static int __devinit 506489a36810SAnil Ravindranath pmcraid_allocate_config_buffers(struct pmcraid_instance *pinstance) 506589a36810SAnil Ravindranath { 506689a36810SAnil Ravindranath int i; 506789a36810SAnil Ravindranath 506889a36810SAnil Ravindranath pinstance->res_entries = 506989a36810SAnil Ravindranath kzalloc(sizeof(struct pmcraid_resource_entry) * 507089a36810SAnil Ravindranath PMCRAID_MAX_RESOURCES, GFP_KERNEL); 507189a36810SAnil Ravindranath 507289a36810SAnil Ravindranath if (NULL == pinstance->res_entries) { 507389a36810SAnil Ravindranath pmcraid_err("failed to allocate memory for resource table\n"); 507489a36810SAnil Ravindranath return -ENOMEM; 507589a36810SAnil Ravindranath } 507689a36810SAnil Ravindranath 507789a36810SAnil Ravindranath for (i = 0; i < PMCRAID_MAX_RESOURCES; i++) 507889a36810SAnil Ravindranath list_add_tail(&pinstance->res_entries[i].queue, 507989a36810SAnil Ravindranath &pinstance->free_res_q); 508089a36810SAnil Ravindranath 508189a36810SAnil Ravindranath pinstance->cfg_table = 508289a36810SAnil Ravindranath pci_alloc_consistent(pinstance->pdev, 508389a36810SAnil Ravindranath sizeof(struct pmcraid_config_table), 508489a36810SAnil Ravindranath &pinstance->cfg_table_bus_addr); 508589a36810SAnil Ravindranath 508689a36810SAnil Ravindranath if (NULL == pinstance->cfg_table) { 508789a36810SAnil Ravindranath pmcraid_err("couldn't alloc DMA memory for config table\n"); 508889a36810SAnil Ravindranath pmcraid_release_config_buffers(pinstance); 508989a36810SAnil Ravindranath return -ENOMEM; 509089a36810SAnil Ravindranath } 509189a36810SAnil Ravindranath 509289a36810SAnil Ravindranath if (pmcraid_allocate_hcams(pinstance)) { 509389a36810SAnil Ravindranath pmcraid_err("could not alloc DMA memory for HCAMS\n"); 509489a36810SAnil Ravindranath pmcraid_release_config_buffers(pinstance); 509589a36810SAnil Ravindranath return -ENOMEM; 509689a36810SAnil Ravindranath } 509789a36810SAnil Ravindranath 509889a36810SAnil Ravindranath return 0; 509989a36810SAnil Ravindranath } 510089a36810SAnil Ravindranath 510189a36810SAnil Ravindranath /** 510289a36810SAnil Ravindranath * pmcraid_init_tasklets - registers tasklets for response handling 510389a36810SAnil Ravindranath * 510489a36810SAnil Ravindranath * @pinstance: pointer adapter instance structure 510589a36810SAnil Ravindranath * 510689a36810SAnil Ravindranath * Return value 510789a36810SAnil Ravindranath * none 510889a36810SAnil Ravindranath */ 510989a36810SAnil Ravindranath static void pmcraid_init_tasklets(struct pmcraid_instance *pinstance) 511089a36810SAnil Ravindranath { 511189a36810SAnil Ravindranath int i; 511289a36810SAnil Ravindranath for (i = 0; i < pinstance->num_hrrq; i++) 511389a36810SAnil Ravindranath tasklet_init(&pinstance->isr_tasklet[i], 511489a36810SAnil Ravindranath pmcraid_tasklet_function, 511589a36810SAnil Ravindranath (unsigned long)&pinstance->hrrq_vector[i]); 511689a36810SAnil Ravindranath } 511789a36810SAnil Ravindranath 511889a36810SAnil Ravindranath /** 511989a36810SAnil Ravindranath * pmcraid_kill_tasklets - destroys tasklets registered for response handling 512089a36810SAnil Ravindranath * 512189a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 512289a36810SAnil Ravindranath * 512389a36810SAnil Ravindranath * Return value 512489a36810SAnil Ravindranath * none 512589a36810SAnil Ravindranath */ 512689a36810SAnil Ravindranath static void pmcraid_kill_tasklets(struct pmcraid_instance *pinstance) 512789a36810SAnil Ravindranath { 512889a36810SAnil Ravindranath int i; 512989a36810SAnil Ravindranath for (i = 0; i < pinstance->num_hrrq; i++) 513089a36810SAnil Ravindranath tasklet_kill(&pinstance->isr_tasklet[i]); 513189a36810SAnil Ravindranath } 513289a36810SAnil Ravindranath 513389a36810SAnil Ravindranath /** 5134c20c4267SAnil Ravindranath * pmcraid_release_buffers - release per-adapter buffers allocated 5135c20c4267SAnil Ravindranath * 5136c20c4267SAnil Ravindranath * @pinstance: pointer to adapter soft state 5137c20c4267SAnil Ravindranath * 5138c20c4267SAnil Ravindranath * Return Value 5139c20c4267SAnil Ravindranath * none 5140c20c4267SAnil Ravindranath */ 5141c20c4267SAnil Ravindranath static void pmcraid_release_buffers(struct pmcraid_instance *pinstance) 5142c20c4267SAnil Ravindranath { 5143c20c4267SAnil Ravindranath pmcraid_release_config_buffers(pinstance); 5144c20c4267SAnil Ravindranath pmcraid_release_control_blocks(pinstance, PMCRAID_MAX_CMD); 5145c20c4267SAnil Ravindranath pmcraid_release_cmd_blocks(pinstance, PMCRAID_MAX_CMD); 5146c20c4267SAnil Ravindranath pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); 5147c20c4267SAnil Ravindranath 5148c20c4267SAnil Ravindranath if (pinstance->inq_data != NULL) { 5149c20c4267SAnil Ravindranath pci_free_consistent(pinstance->pdev, 5150c20c4267SAnil Ravindranath sizeof(struct pmcraid_inquiry_data), 5151c20c4267SAnil Ravindranath pinstance->inq_data, 5152c20c4267SAnil Ravindranath pinstance->inq_data_baddr); 5153c20c4267SAnil Ravindranath 5154c20c4267SAnil Ravindranath pinstance->inq_data = NULL; 5155c20c4267SAnil Ravindranath pinstance->inq_data_baddr = 0; 5156c20c4267SAnil Ravindranath } 5157592488a3SAnil Ravindranath 5158592488a3SAnil Ravindranath if (pinstance->timestamp_data != NULL) { 5159592488a3SAnil Ravindranath pci_free_consistent(pinstance->pdev, 5160592488a3SAnil Ravindranath sizeof(struct pmcraid_timestamp_data), 5161592488a3SAnil Ravindranath pinstance->timestamp_data, 5162592488a3SAnil Ravindranath pinstance->timestamp_data_baddr); 5163592488a3SAnil Ravindranath 5164592488a3SAnil Ravindranath pinstance->timestamp_data = NULL; 5165592488a3SAnil Ravindranath pinstance->timestamp_data_baddr = 0; 5166592488a3SAnil Ravindranath } 5167c20c4267SAnil Ravindranath } 5168c20c4267SAnil Ravindranath 5169c20c4267SAnil Ravindranath /** 517089a36810SAnil Ravindranath * pmcraid_init_buffers - allocates memory and initializes various structures 517189a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 517289a36810SAnil Ravindranath * 517389a36810SAnil Ravindranath * This routine pre-allocates memory based on the type of block as below: 517489a36810SAnil Ravindranath * cmdblocks(PMCRAID_MAX_CMD): kernel memory using kernel's slab_allocator, 517589a36810SAnil Ravindranath * IOARCBs(PMCRAID_MAX_CMD) : DMAable memory, using pci pool allocator 517689a36810SAnil Ravindranath * config-table entries : DMAable memory using pci_alloc_consistent 517789a36810SAnil Ravindranath * HostRRQs : DMAable memory, using pci_alloc_consistent 517889a36810SAnil Ravindranath * 517989a36810SAnil Ravindranath * Return Value 518089a36810SAnil Ravindranath * 0 in case all of the blocks are allocated, -ENOMEM otherwise. 518189a36810SAnil Ravindranath */ 518289a36810SAnil Ravindranath static int __devinit pmcraid_init_buffers(struct pmcraid_instance *pinstance) 518389a36810SAnil Ravindranath { 518489a36810SAnil Ravindranath int i; 518589a36810SAnil Ravindranath 518689a36810SAnil Ravindranath if (pmcraid_allocate_host_rrqs(pinstance)) { 518789a36810SAnil Ravindranath pmcraid_err("couldn't allocate memory for %d host rrqs\n", 518889a36810SAnil Ravindranath pinstance->num_hrrq); 518989a36810SAnil Ravindranath return -ENOMEM; 519089a36810SAnil Ravindranath } 519189a36810SAnil Ravindranath 519289a36810SAnil Ravindranath if (pmcraid_allocate_config_buffers(pinstance)) { 519389a36810SAnil Ravindranath pmcraid_err("couldn't allocate memory for config buffers\n"); 519489a36810SAnil Ravindranath pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); 519589a36810SAnil Ravindranath return -ENOMEM; 519689a36810SAnil Ravindranath } 519789a36810SAnil Ravindranath 519889a36810SAnil Ravindranath if (pmcraid_allocate_cmd_blocks(pinstance)) { 519989a36810SAnil Ravindranath pmcraid_err("couldn't allocate memory for cmd blocks\n"); 520089a36810SAnil Ravindranath pmcraid_release_config_buffers(pinstance); 520189a36810SAnil Ravindranath pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); 520289a36810SAnil Ravindranath return -ENOMEM; 520389a36810SAnil Ravindranath } 520489a36810SAnil Ravindranath 520589a36810SAnil Ravindranath if (pmcraid_allocate_control_blocks(pinstance)) { 520689a36810SAnil Ravindranath pmcraid_err("couldn't allocate memory control blocks\n"); 520789a36810SAnil Ravindranath pmcraid_release_config_buffers(pinstance); 520889a36810SAnil Ravindranath pmcraid_release_cmd_blocks(pinstance, PMCRAID_MAX_CMD); 520989a36810SAnil Ravindranath pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); 521089a36810SAnil Ravindranath return -ENOMEM; 521189a36810SAnil Ravindranath } 521289a36810SAnil Ravindranath 5213c20c4267SAnil Ravindranath /* allocate DMAable memory for page D0 INQUIRY buffer */ 5214c20c4267SAnil Ravindranath pinstance->inq_data = pci_alloc_consistent( 5215c20c4267SAnil Ravindranath pinstance->pdev, 5216c20c4267SAnil Ravindranath sizeof(struct pmcraid_inquiry_data), 5217c20c4267SAnil Ravindranath &pinstance->inq_data_baddr); 5218c20c4267SAnil Ravindranath 5219c20c4267SAnil Ravindranath if (pinstance->inq_data == NULL) { 5220c20c4267SAnil Ravindranath pmcraid_err("couldn't allocate DMA memory for INQUIRY\n"); 5221c20c4267SAnil Ravindranath pmcraid_release_buffers(pinstance); 5222c20c4267SAnil Ravindranath return -ENOMEM; 5223c20c4267SAnil Ravindranath } 5224c20c4267SAnil Ravindranath 5225592488a3SAnil Ravindranath /* allocate DMAable memory for set timestamp data buffer */ 5226592488a3SAnil Ravindranath pinstance->timestamp_data = pci_alloc_consistent( 5227592488a3SAnil Ravindranath pinstance->pdev, 5228592488a3SAnil Ravindranath sizeof(struct pmcraid_timestamp_data), 5229592488a3SAnil Ravindranath &pinstance->timestamp_data_baddr); 5230592488a3SAnil Ravindranath 5231592488a3SAnil Ravindranath if (pinstance->timestamp_data == NULL) { 5232592488a3SAnil Ravindranath pmcraid_err("couldn't allocate DMA memory for \ 5233592488a3SAnil Ravindranath set time_stamp \n"); 5234592488a3SAnil Ravindranath pmcraid_release_buffers(pinstance); 5235592488a3SAnil Ravindranath return -ENOMEM; 5236592488a3SAnil Ravindranath } 5237592488a3SAnil Ravindranath 5238592488a3SAnil Ravindranath 523989a36810SAnil Ravindranath /* Initialize all the command blocks and add them to free pool. No 524089a36810SAnil Ravindranath * need to lock (free_pool_lock) as this is done in initialization 524189a36810SAnil Ravindranath * itself 524289a36810SAnil Ravindranath */ 524389a36810SAnil Ravindranath for (i = 0; i < PMCRAID_MAX_CMD; i++) { 524489a36810SAnil Ravindranath struct pmcraid_cmd *cmdp = pinstance->cmd_list[i]; 524589a36810SAnil Ravindranath pmcraid_init_cmdblk(cmdp, i); 524689a36810SAnil Ravindranath cmdp->drv_inst = pinstance; 524789a36810SAnil Ravindranath list_add_tail(&cmdp->free_list, &pinstance->free_cmd_pool); 524889a36810SAnil Ravindranath } 524989a36810SAnil Ravindranath 525089a36810SAnil Ravindranath return 0; 525189a36810SAnil Ravindranath } 525289a36810SAnil Ravindranath 525389a36810SAnil Ravindranath /** 525489a36810SAnil Ravindranath * pmcraid_reinit_buffers - resets various buffer pointers 525589a36810SAnil Ravindranath * @pinstance: pointer to adapter instance 525689a36810SAnil Ravindranath * Return value 525789a36810SAnil Ravindranath * none 525889a36810SAnil Ravindranath */ 525989a36810SAnil Ravindranath static void pmcraid_reinit_buffers(struct pmcraid_instance *pinstance) 526089a36810SAnil Ravindranath { 526189a36810SAnil Ravindranath int i; 526289a36810SAnil Ravindranath int buffer_size = HRRQ_ENTRY_SIZE * PMCRAID_MAX_CMD; 526389a36810SAnil Ravindranath 526489a36810SAnil Ravindranath for (i = 0; i < pinstance->num_hrrq; i++) { 526589a36810SAnil Ravindranath memset(pinstance->hrrq_start[i], 0, buffer_size); 526689a36810SAnil Ravindranath pinstance->hrrq_curr[i] = pinstance->hrrq_start[i]; 526789a36810SAnil Ravindranath pinstance->hrrq_end[i] = 526889a36810SAnil Ravindranath pinstance->hrrq_start[i] + PMCRAID_MAX_CMD - 1; 526989a36810SAnil Ravindranath pinstance->host_toggle_bit[i] = 1; 527089a36810SAnil Ravindranath } 527189a36810SAnil Ravindranath } 527289a36810SAnil Ravindranath 527389a36810SAnil Ravindranath /** 527489a36810SAnil Ravindranath * pmcraid_init_instance - initialize per instance data structure 527589a36810SAnil Ravindranath * @pdev: pointer to pci device structure 527689a36810SAnil Ravindranath * @host: pointer to Scsi_Host structure 527789a36810SAnil Ravindranath * @mapped_pci_addr: memory mapped IOA configuration registers 527889a36810SAnil Ravindranath * 527989a36810SAnil Ravindranath * Return Value 528089a36810SAnil Ravindranath * 0 on success, non-zero in case of any failure 528189a36810SAnil Ravindranath */ 528289a36810SAnil Ravindranath static int __devinit pmcraid_init_instance( 528389a36810SAnil Ravindranath struct pci_dev *pdev, 528489a36810SAnil Ravindranath struct Scsi_Host *host, 528589a36810SAnil Ravindranath void __iomem *mapped_pci_addr 528689a36810SAnil Ravindranath ) 528789a36810SAnil Ravindranath { 528889a36810SAnil Ravindranath struct pmcraid_instance *pinstance = 528989a36810SAnil Ravindranath (struct pmcraid_instance *)host->hostdata; 529089a36810SAnil Ravindranath 529189a36810SAnil Ravindranath pinstance->host = host; 529289a36810SAnil Ravindranath pinstance->pdev = pdev; 529389a36810SAnil Ravindranath 529489a36810SAnil Ravindranath /* Initialize register addresses */ 529589a36810SAnil Ravindranath pinstance->mapped_dma_addr = mapped_pci_addr; 529689a36810SAnil Ravindranath 529789a36810SAnil Ravindranath /* Initialize chip-specific details */ 529889a36810SAnil Ravindranath { 529989a36810SAnil Ravindranath struct pmcraid_chip_details *chip_cfg = pinstance->chip_cfg; 530089a36810SAnil Ravindranath struct pmcraid_interrupts *pint_regs = &pinstance->int_regs; 530189a36810SAnil Ravindranath 530289a36810SAnil Ravindranath pinstance->ioarrin = mapped_pci_addr + chip_cfg->ioarrin; 530389a36810SAnil Ravindranath 530489a36810SAnil Ravindranath pint_regs->ioa_host_interrupt_reg = 530589a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->ioa_host_intr; 530689a36810SAnil Ravindranath pint_regs->ioa_host_interrupt_clr_reg = 530789a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->ioa_host_intr_clr; 5308c20c4267SAnil Ravindranath pint_regs->ioa_host_msix_interrupt_reg = 5309c20c4267SAnil Ravindranath mapped_pci_addr + chip_cfg->ioa_host_msix_intr; 531089a36810SAnil Ravindranath pint_regs->host_ioa_interrupt_reg = 531189a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->host_ioa_intr; 531289a36810SAnil Ravindranath pint_regs->host_ioa_interrupt_clr_reg = 531389a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->host_ioa_intr_clr; 531489a36810SAnil Ravindranath 531589a36810SAnil Ravindranath /* Current version of firmware exposes interrupt mask set 531689a36810SAnil Ravindranath * and mask clr registers through memory mapped bar0. 531789a36810SAnil Ravindranath */ 531889a36810SAnil Ravindranath pinstance->mailbox = mapped_pci_addr + chip_cfg->mailbox; 531989a36810SAnil Ravindranath pinstance->ioa_status = mapped_pci_addr + chip_cfg->ioastatus; 532089a36810SAnil Ravindranath pint_regs->ioa_host_interrupt_mask_reg = 532189a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->ioa_host_mask; 532289a36810SAnil Ravindranath pint_regs->ioa_host_interrupt_mask_clr_reg = 532389a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->ioa_host_mask_clr; 532489a36810SAnil Ravindranath pint_regs->global_interrupt_mask_reg = 532589a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->global_intr_mask; 532689a36810SAnil Ravindranath }; 532789a36810SAnil Ravindranath 532889a36810SAnil Ravindranath pinstance->ioa_reset_attempts = 0; 532989a36810SAnil Ravindranath init_waitqueue_head(&pinstance->reset_wait_q); 533089a36810SAnil Ravindranath 533189a36810SAnil Ravindranath atomic_set(&pinstance->outstanding_cmds, 0); 5332c20c4267SAnil Ravindranath atomic_set(&pinstance->last_message_id, 0); 533389a36810SAnil Ravindranath atomic_set(&pinstance->expose_resources, 0); 533489a36810SAnil Ravindranath 533589a36810SAnil Ravindranath INIT_LIST_HEAD(&pinstance->free_res_q); 533689a36810SAnil Ravindranath INIT_LIST_HEAD(&pinstance->used_res_q); 533789a36810SAnil Ravindranath INIT_LIST_HEAD(&pinstance->free_cmd_pool); 533889a36810SAnil Ravindranath INIT_LIST_HEAD(&pinstance->pending_cmd_pool); 533989a36810SAnil Ravindranath 534089a36810SAnil Ravindranath spin_lock_init(&pinstance->free_pool_lock); 534189a36810SAnil Ravindranath spin_lock_init(&pinstance->pending_pool_lock); 534289a36810SAnil Ravindranath spin_lock_init(&pinstance->resource_lock); 534389a36810SAnil Ravindranath mutex_init(&pinstance->aen_queue_lock); 534489a36810SAnil Ravindranath 534589a36810SAnil Ravindranath /* Work-queue (Shared) for deferred processing error handling */ 534689a36810SAnil Ravindranath INIT_WORK(&pinstance->worker_q, pmcraid_worker_function); 534789a36810SAnil Ravindranath 534889a36810SAnil Ravindranath /* Initialize the default log_level */ 534989a36810SAnil Ravindranath pinstance->current_log_level = pmcraid_log_level; 535089a36810SAnil Ravindranath 535189a36810SAnil Ravindranath /* Setup variables required for reset engine */ 535289a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_UNKNOWN; 535389a36810SAnil Ravindranath pinstance->reset_cmd = NULL; 535489a36810SAnil Ravindranath return 0; 535589a36810SAnil Ravindranath } 535689a36810SAnil Ravindranath 535789a36810SAnil Ravindranath /** 535889a36810SAnil Ravindranath * pmcraid_shutdown - shutdown adapter controller. 535989a36810SAnil Ravindranath * @pdev: pci device struct 536089a36810SAnil Ravindranath * 536189a36810SAnil Ravindranath * Issues an adapter shutdown to the card waits for its completion 536289a36810SAnil Ravindranath * 536389a36810SAnil Ravindranath * Return value 536489a36810SAnil Ravindranath * none 536589a36810SAnil Ravindranath */ 536689a36810SAnil Ravindranath static void pmcraid_shutdown(struct pci_dev *pdev) 536789a36810SAnil Ravindranath { 536889a36810SAnil Ravindranath struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); 536989a36810SAnil Ravindranath pmcraid_reset_bringdown(pinstance); 537089a36810SAnil Ravindranath } 537189a36810SAnil Ravindranath 537289a36810SAnil Ravindranath 537389a36810SAnil Ravindranath /** 537489a36810SAnil Ravindranath * pmcraid_get_minor - returns unused minor number from minor number bitmap 537589a36810SAnil Ravindranath */ 537689a36810SAnil Ravindranath static unsigned short pmcraid_get_minor(void) 537789a36810SAnil Ravindranath { 537889a36810SAnil Ravindranath int minor; 537989a36810SAnil Ravindranath 538089a36810SAnil Ravindranath minor = find_first_zero_bit(pmcraid_minor, sizeof(pmcraid_minor)); 538189a36810SAnil Ravindranath __set_bit(minor, pmcraid_minor); 538289a36810SAnil Ravindranath return minor; 538389a36810SAnil Ravindranath } 538489a36810SAnil Ravindranath 538589a36810SAnil Ravindranath /** 538689a36810SAnil Ravindranath * pmcraid_release_minor - releases given minor back to minor number bitmap 538789a36810SAnil Ravindranath */ 538889a36810SAnil Ravindranath static void pmcraid_release_minor(unsigned short minor) 538989a36810SAnil Ravindranath { 539089a36810SAnil Ravindranath __clear_bit(minor, pmcraid_minor); 539189a36810SAnil Ravindranath } 539289a36810SAnil Ravindranath 539389a36810SAnil Ravindranath /** 539489a36810SAnil Ravindranath * pmcraid_setup_chrdev - allocates a minor number and registers a char device 539589a36810SAnil Ravindranath * 539689a36810SAnil Ravindranath * @pinstance: pointer to adapter instance for which to register device 539789a36810SAnil Ravindranath * 539889a36810SAnil Ravindranath * Return value 539989a36810SAnil Ravindranath * 0 in case of success, otherwise non-zero 540089a36810SAnil Ravindranath */ 540189a36810SAnil Ravindranath static int pmcraid_setup_chrdev(struct pmcraid_instance *pinstance) 540289a36810SAnil Ravindranath { 540389a36810SAnil Ravindranath int minor; 540489a36810SAnil Ravindranath int error; 540589a36810SAnil Ravindranath 540689a36810SAnil Ravindranath minor = pmcraid_get_minor(); 540789a36810SAnil Ravindranath cdev_init(&pinstance->cdev, &pmcraid_fops); 540889a36810SAnil Ravindranath pinstance->cdev.owner = THIS_MODULE; 540989a36810SAnil Ravindranath 541089a36810SAnil Ravindranath error = cdev_add(&pinstance->cdev, MKDEV(pmcraid_major, minor), 1); 541189a36810SAnil Ravindranath 541289a36810SAnil Ravindranath if (error) 541389a36810SAnil Ravindranath pmcraid_release_minor(minor); 541489a36810SAnil Ravindranath else 541589a36810SAnil Ravindranath device_create(pmcraid_class, NULL, MKDEV(pmcraid_major, minor), 5416c20c4267SAnil Ravindranath NULL, "%s%u", PMCRAID_DEVFILE, minor); 541789a36810SAnil Ravindranath return error; 541889a36810SAnil Ravindranath } 541989a36810SAnil Ravindranath 542089a36810SAnil Ravindranath /** 542189a36810SAnil Ravindranath * pmcraid_release_chrdev - unregisters per-adapter management interface 542289a36810SAnil Ravindranath * 542389a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 542489a36810SAnil Ravindranath * 542589a36810SAnil Ravindranath * Return value 542689a36810SAnil Ravindranath * none 542789a36810SAnil Ravindranath */ 542889a36810SAnil Ravindranath static void pmcraid_release_chrdev(struct pmcraid_instance *pinstance) 542989a36810SAnil Ravindranath { 543089a36810SAnil Ravindranath pmcraid_release_minor(MINOR(pinstance->cdev.dev)); 543189a36810SAnil Ravindranath device_destroy(pmcraid_class, 543289a36810SAnil Ravindranath MKDEV(pmcraid_major, MINOR(pinstance->cdev.dev))); 543389a36810SAnil Ravindranath cdev_del(&pinstance->cdev); 543489a36810SAnil Ravindranath } 543589a36810SAnil Ravindranath 543689a36810SAnil Ravindranath /** 543789a36810SAnil Ravindranath * pmcraid_remove - IOA hot plug remove entry point 543889a36810SAnil Ravindranath * @pdev: pci device struct 543989a36810SAnil Ravindranath * 544089a36810SAnil Ravindranath * Return value 544189a36810SAnil Ravindranath * none 544289a36810SAnil Ravindranath */ 544389a36810SAnil Ravindranath static void __devexit pmcraid_remove(struct pci_dev *pdev) 544489a36810SAnil Ravindranath { 544589a36810SAnil Ravindranath struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); 544689a36810SAnil Ravindranath 544789a36810SAnil Ravindranath /* remove the management interface (/dev file) for this device */ 544889a36810SAnil Ravindranath pmcraid_release_chrdev(pinstance); 544989a36810SAnil Ravindranath 545089a36810SAnil Ravindranath /* remove host template from scsi midlayer */ 545189a36810SAnil Ravindranath scsi_remove_host(pinstance->host); 545289a36810SAnil Ravindranath 545389a36810SAnil Ravindranath /* block requests from mid-layer */ 545489a36810SAnil Ravindranath scsi_block_requests(pinstance->host); 545589a36810SAnil Ravindranath 545689a36810SAnil Ravindranath /* initiate shutdown adapter */ 545789a36810SAnil Ravindranath pmcraid_shutdown(pdev); 545889a36810SAnil Ravindranath 545989a36810SAnil Ravindranath pmcraid_disable_interrupts(pinstance, ~0); 5460a684b8daSTejun Heo flush_work_sync(&pinstance->worker_q); 546189a36810SAnil Ravindranath 546289a36810SAnil Ravindranath pmcraid_kill_tasklets(pinstance); 546389a36810SAnil Ravindranath pmcraid_unregister_interrupt_handler(pinstance); 546489a36810SAnil Ravindranath pmcraid_release_buffers(pinstance); 546589a36810SAnil Ravindranath iounmap(pinstance->mapped_dma_addr); 546689a36810SAnil Ravindranath pci_release_regions(pdev); 546789a36810SAnil Ravindranath scsi_host_put(pinstance->host); 546889a36810SAnil Ravindranath pci_disable_device(pdev); 546989a36810SAnil Ravindranath 547089a36810SAnil Ravindranath return; 547189a36810SAnil Ravindranath } 547289a36810SAnil Ravindranath 547389a36810SAnil Ravindranath #ifdef CONFIG_PM 547489a36810SAnil Ravindranath /** 547589a36810SAnil Ravindranath * pmcraid_suspend - driver suspend entry point for power management 547689a36810SAnil Ravindranath * @pdev: PCI device structure 547789a36810SAnil Ravindranath * @state: PCI power state to suspend routine 547889a36810SAnil Ravindranath * 547989a36810SAnil Ravindranath * Return Value - 0 always 548089a36810SAnil Ravindranath */ 548189a36810SAnil Ravindranath static int pmcraid_suspend(struct pci_dev *pdev, pm_message_t state) 548289a36810SAnil Ravindranath { 548389a36810SAnil Ravindranath struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); 548489a36810SAnil Ravindranath 548589a36810SAnil Ravindranath pmcraid_shutdown(pdev); 548689a36810SAnil Ravindranath pmcraid_disable_interrupts(pinstance, ~0); 548789a36810SAnil Ravindranath pmcraid_kill_tasklets(pinstance); 548889a36810SAnil Ravindranath pci_set_drvdata(pinstance->pdev, pinstance); 548989a36810SAnil Ravindranath pmcraid_unregister_interrupt_handler(pinstance); 549089a36810SAnil Ravindranath pci_save_state(pdev); 549189a36810SAnil Ravindranath pci_disable_device(pdev); 549289a36810SAnil Ravindranath pci_set_power_state(pdev, pci_choose_state(pdev, state)); 549389a36810SAnil Ravindranath 549489a36810SAnil Ravindranath return 0; 549589a36810SAnil Ravindranath } 549689a36810SAnil Ravindranath 549789a36810SAnil Ravindranath /** 549889a36810SAnil Ravindranath * pmcraid_resume - driver resume entry point PCI power management 549989a36810SAnil Ravindranath * @pdev: PCI device structure 550089a36810SAnil Ravindranath * 550189a36810SAnil Ravindranath * Return Value - 0 in case of success. Error code in case of any failure 550289a36810SAnil Ravindranath */ 550389a36810SAnil Ravindranath static int pmcraid_resume(struct pci_dev *pdev) 550489a36810SAnil Ravindranath { 550589a36810SAnil Ravindranath struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); 550689a36810SAnil Ravindranath struct Scsi_Host *host = pinstance->host; 550789a36810SAnil Ravindranath int rc; 550889a36810SAnil Ravindranath 550989a36810SAnil Ravindranath pci_set_power_state(pdev, PCI_D0); 551089a36810SAnil Ravindranath pci_enable_wake(pdev, PCI_D0, 0); 551189a36810SAnil Ravindranath pci_restore_state(pdev); 551289a36810SAnil Ravindranath 551389a36810SAnil Ravindranath rc = pci_enable_device(pdev); 551489a36810SAnil Ravindranath 551589a36810SAnil Ravindranath if (rc) { 551634876402SAnil Ravindranath dev_err(&pdev->dev, "resume: Enable device failed\n"); 551789a36810SAnil Ravindranath return rc; 551889a36810SAnil Ravindranath } 551989a36810SAnil Ravindranath 552089a36810SAnil Ravindranath pci_set_master(pdev); 552189a36810SAnil Ravindranath 552289a36810SAnil Ravindranath if ((sizeof(dma_addr_t) == 4) || 552389a36810SAnil Ravindranath pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) 552489a36810SAnil Ravindranath rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 552589a36810SAnil Ravindranath 552689a36810SAnil Ravindranath if (rc == 0) 552789a36810SAnil Ravindranath rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); 552889a36810SAnil Ravindranath 552989a36810SAnil Ravindranath if (rc != 0) { 553034876402SAnil Ravindranath dev_err(&pdev->dev, "resume: Failed to set PCI DMA mask\n"); 553189a36810SAnil Ravindranath goto disable_device; 553289a36810SAnil Ravindranath } 553389a36810SAnil Ravindranath 5534c20c4267SAnil Ravindranath pmcraid_disable_interrupts(pinstance, ~0); 553589a36810SAnil Ravindranath atomic_set(&pinstance->outstanding_cmds, 0); 553689a36810SAnil Ravindranath rc = pmcraid_register_interrupt_handler(pinstance); 553789a36810SAnil Ravindranath 553889a36810SAnil Ravindranath if (rc) { 553934876402SAnil Ravindranath dev_err(&pdev->dev, 554034876402SAnil Ravindranath "resume: couldn't register interrupt handlers\n"); 554189a36810SAnil Ravindranath rc = -ENODEV; 554289a36810SAnil Ravindranath goto release_host; 554389a36810SAnil Ravindranath } 554489a36810SAnil Ravindranath 554589a36810SAnil Ravindranath pmcraid_init_tasklets(pinstance); 554689a36810SAnil Ravindranath pmcraid_enable_interrupts(pinstance, PMCRAID_PCI_INTERRUPTS); 554789a36810SAnil Ravindranath 554889a36810SAnil Ravindranath /* Start with hard reset sequence which brings up IOA to operational 554989a36810SAnil Ravindranath * state as well as completes the reset sequence. 555089a36810SAnil Ravindranath */ 555189a36810SAnil Ravindranath pinstance->ioa_hard_reset = 1; 555289a36810SAnil Ravindranath 555389a36810SAnil Ravindranath /* Start IOA firmware initialization and bring card to Operational 555489a36810SAnil Ravindranath * state. 555589a36810SAnil Ravindranath */ 555689a36810SAnil Ravindranath if (pmcraid_reset_bringup(pinstance)) { 555734876402SAnil Ravindranath dev_err(&pdev->dev, "couldn't initialize IOA\n"); 555889a36810SAnil Ravindranath rc = -ENODEV; 555989a36810SAnil Ravindranath goto release_tasklets; 556089a36810SAnil Ravindranath } 556189a36810SAnil Ravindranath 556289a36810SAnil Ravindranath return 0; 556389a36810SAnil Ravindranath 556489a36810SAnil Ravindranath release_tasklets: 5565c20c4267SAnil Ravindranath pmcraid_disable_interrupts(pinstance, ~0); 556689a36810SAnil Ravindranath pmcraid_kill_tasklets(pinstance); 556789a36810SAnil Ravindranath pmcraid_unregister_interrupt_handler(pinstance); 556889a36810SAnil Ravindranath 556989a36810SAnil Ravindranath release_host: 557089a36810SAnil Ravindranath scsi_host_put(host); 557189a36810SAnil Ravindranath 557289a36810SAnil Ravindranath disable_device: 557389a36810SAnil Ravindranath pci_disable_device(pdev); 557489a36810SAnil Ravindranath 557589a36810SAnil Ravindranath return rc; 557689a36810SAnil Ravindranath } 557789a36810SAnil Ravindranath 557889a36810SAnil Ravindranath #else 557989a36810SAnil Ravindranath 558089a36810SAnil Ravindranath #define pmcraid_suspend NULL 558189a36810SAnil Ravindranath #define pmcraid_resume NULL 558289a36810SAnil Ravindranath 558389a36810SAnil Ravindranath #endif /* CONFIG_PM */ 558489a36810SAnil Ravindranath 558589a36810SAnil Ravindranath /** 558689a36810SAnil Ravindranath * pmcraid_complete_ioa_reset - Called by either timer or tasklet during 558789a36810SAnil Ravindranath * completion of the ioa reset 558889a36810SAnil Ravindranath * @cmd: pointer to reset command block 558989a36810SAnil Ravindranath */ 559089a36810SAnil Ravindranath static void pmcraid_complete_ioa_reset(struct pmcraid_cmd *cmd) 559189a36810SAnil Ravindranath { 559289a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 559389a36810SAnil Ravindranath unsigned long flags; 559489a36810SAnil Ravindranath 559589a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, flags); 559689a36810SAnil Ravindranath pmcraid_ioa_reset(cmd); 559789a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, flags); 559889a36810SAnil Ravindranath scsi_unblock_requests(pinstance->host); 559989a36810SAnil Ravindranath schedule_work(&pinstance->worker_q); 560089a36810SAnil Ravindranath } 560189a36810SAnil Ravindranath 560289a36810SAnil Ravindranath /** 560389a36810SAnil Ravindranath * pmcraid_set_supported_devs - sends SET SUPPORTED DEVICES to IOAFP 560489a36810SAnil Ravindranath * 560589a36810SAnil Ravindranath * @cmd: pointer to pmcraid_cmd structure 560689a36810SAnil Ravindranath * 560789a36810SAnil Ravindranath * Return Value 560889a36810SAnil Ravindranath * 0 for success or non-zero for failure cases 560989a36810SAnil Ravindranath */ 561089a36810SAnil Ravindranath static void pmcraid_set_supported_devs(struct pmcraid_cmd *cmd) 561189a36810SAnil Ravindranath { 561289a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 561389a36810SAnil Ravindranath void (*cmd_done) (struct pmcraid_cmd *) = pmcraid_complete_ioa_reset; 561489a36810SAnil Ravindranath 561589a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 561689a36810SAnil Ravindranath 561789a36810SAnil Ravindranath ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); 561889a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_IOACMD; 561989a36810SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_SET_SUPPORTED_DEVICES; 562089a36810SAnil Ravindranath ioarcb->cdb[1] = ALL_DEVICES_SUPPORTED; 562189a36810SAnil Ravindranath 562289a36810SAnil Ravindranath /* If this was called as part of resource table reinitialization due to 562389a36810SAnil Ravindranath * lost CCN, it is enough to return the command block back to free pool 562489a36810SAnil Ravindranath * as part of set_supported_devs completion function. 562589a36810SAnil Ravindranath */ 562689a36810SAnil Ravindranath if (cmd->drv_inst->reinit_cfg_table) { 562789a36810SAnil Ravindranath cmd->drv_inst->reinit_cfg_table = 0; 562889a36810SAnil Ravindranath cmd->release = 1; 562989a36810SAnil Ravindranath cmd_done = pmcraid_reinit_cfgtable_done; 563089a36810SAnil Ravindranath } 563189a36810SAnil Ravindranath 563289a36810SAnil Ravindranath /* we will be done with the reset sequence after set supported devices, 563389a36810SAnil Ravindranath * setup the done function to return the command block back to free 563489a36810SAnil Ravindranath * pool 563589a36810SAnil Ravindranath */ 563689a36810SAnil Ravindranath pmcraid_send_cmd(cmd, 563789a36810SAnil Ravindranath cmd_done, 563889a36810SAnil Ravindranath PMCRAID_SET_SUP_DEV_TIMEOUT, 563989a36810SAnil Ravindranath pmcraid_timeout_handler); 564089a36810SAnil Ravindranath return; 564189a36810SAnil Ravindranath } 564289a36810SAnil Ravindranath 564389a36810SAnil Ravindranath /** 5644592488a3SAnil Ravindranath * pmcraid_set_timestamp - set the timestamp to IOAFP 5645592488a3SAnil Ravindranath * 5646592488a3SAnil Ravindranath * @cmd: pointer to pmcraid_cmd structure 5647592488a3SAnil Ravindranath * 5648592488a3SAnil Ravindranath * Return Value 5649592488a3SAnil Ravindranath * 0 for success or non-zero for failure cases 5650592488a3SAnil Ravindranath */ 5651592488a3SAnil Ravindranath static void pmcraid_set_timestamp(struct pmcraid_cmd *cmd) 5652592488a3SAnil Ravindranath { 5653592488a3SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 5654592488a3SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 5655592488a3SAnil Ravindranath __be32 time_stamp_len = cpu_to_be32(PMCRAID_TIMESTAMP_LEN); 5656592488a3SAnil Ravindranath struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; 5657592488a3SAnil Ravindranath 5658592488a3SAnil Ravindranath struct timeval tv; 5659592488a3SAnil Ravindranath __le64 timestamp; 5660592488a3SAnil Ravindranath 5661592488a3SAnil Ravindranath do_gettimeofday(&tv); 5662592488a3SAnil Ravindranath timestamp = tv.tv_sec * 1000; 5663592488a3SAnil Ravindranath 5664592488a3SAnil Ravindranath pinstance->timestamp_data->timestamp[0] = (__u8)(timestamp); 5665592488a3SAnil Ravindranath pinstance->timestamp_data->timestamp[1] = (__u8)((timestamp) >> 8); 5666592488a3SAnil Ravindranath pinstance->timestamp_data->timestamp[2] = (__u8)((timestamp) >> 16); 5667592488a3SAnil Ravindranath pinstance->timestamp_data->timestamp[3] = (__u8)((timestamp) >> 24); 5668592488a3SAnil Ravindranath pinstance->timestamp_data->timestamp[4] = (__u8)((timestamp) >> 32); 5669592488a3SAnil Ravindranath pinstance->timestamp_data->timestamp[5] = (__u8)((timestamp) >> 40); 5670592488a3SAnil Ravindranath 5671592488a3SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 5672592488a3SAnil Ravindranath ioarcb->request_type = REQ_TYPE_SCSI; 5673592488a3SAnil Ravindranath ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); 5674592488a3SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_SCSI_SET_TIMESTAMP; 5675592488a3SAnil Ravindranath ioarcb->cdb[1] = PMCRAID_SCSI_SERVICE_ACTION; 5676592488a3SAnil Ravindranath memcpy(&(ioarcb->cdb[6]), &time_stamp_len, sizeof(time_stamp_len)); 5677592488a3SAnil Ravindranath 5678592488a3SAnil Ravindranath ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + 5679592488a3SAnil Ravindranath offsetof(struct pmcraid_ioarcb, 5680592488a3SAnil Ravindranath add_data.u.ioadl[0])); 5681592488a3SAnil Ravindranath ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); 5682592488a3SAnil Ravindranath ioarcb->ioarcb_bus_addr &= ~(0x1FULL); 5683592488a3SAnil Ravindranath 5684592488a3SAnil Ravindranath ioarcb->request_flags0 |= NO_LINK_DESCS; 5685592488a3SAnil Ravindranath ioarcb->request_flags0 |= TRANSFER_DIR_WRITE; 5686592488a3SAnil Ravindranath ioarcb->data_transfer_length = 5687592488a3SAnil Ravindranath cpu_to_le32(sizeof(struct pmcraid_timestamp_data)); 5688592488a3SAnil Ravindranath ioadl = &(ioarcb->add_data.u.ioadl[0]); 5689592488a3SAnil Ravindranath ioadl->flags = IOADL_FLAGS_LAST_DESC; 5690592488a3SAnil Ravindranath ioadl->address = cpu_to_le64(pinstance->timestamp_data_baddr); 5691592488a3SAnil Ravindranath ioadl->data_len = cpu_to_le32(sizeof(struct pmcraid_timestamp_data)); 5692592488a3SAnil Ravindranath 5693592488a3SAnil Ravindranath if (!pinstance->timestamp_error) { 5694592488a3SAnil Ravindranath pinstance->timestamp_error = 0; 5695592488a3SAnil Ravindranath pmcraid_send_cmd(cmd, pmcraid_set_supported_devs, 5696592488a3SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler); 5697592488a3SAnil Ravindranath } else { 5698592488a3SAnil Ravindranath pmcraid_send_cmd(cmd, pmcraid_return_cmd, 5699592488a3SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler); 5700592488a3SAnil Ravindranath return; 5701592488a3SAnil Ravindranath } 5702592488a3SAnil Ravindranath } 5703592488a3SAnil Ravindranath 5704592488a3SAnil Ravindranath 5705592488a3SAnil Ravindranath /** 570689a36810SAnil Ravindranath * pmcraid_init_res_table - Initialize the resource table 570789a36810SAnil Ravindranath * @cmd: pointer to pmcraid command struct 570889a36810SAnil Ravindranath * 570989a36810SAnil Ravindranath * This function looks through the existing resource table, comparing 571089a36810SAnil Ravindranath * it with the config table. This function will take care of old/new 571189a36810SAnil Ravindranath * devices and schedule adding/removing them from the mid-layer 571289a36810SAnil Ravindranath * as appropriate. 571389a36810SAnil Ravindranath * 571489a36810SAnil Ravindranath * Return value 571589a36810SAnil Ravindranath * None 571689a36810SAnil Ravindranath */ 571789a36810SAnil Ravindranath static void pmcraid_init_res_table(struct pmcraid_cmd *cmd) 571889a36810SAnil Ravindranath { 571989a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 572089a36810SAnil Ravindranath struct pmcraid_resource_entry *res, *temp; 572189a36810SAnil Ravindranath struct pmcraid_config_table_entry *cfgte; 572289a36810SAnil Ravindranath unsigned long lock_flags; 572389a36810SAnil Ravindranath int found, rc, i; 5724c20c4267SAnil Ravindranath u16 fw_version; 572589a36810SAnil Ravindranath LIST_HEAD(old_res); 572689a36810SAnil Ravindranath 572789a36810SAnil Ravindranath if (pinstance->cfg_table->flags & MICROCODE_UPDATE_REQUIRED) 572834876402SAnil Ravindranath pmcraid_err("IOA requires microcode download\n"); 572989a36810SAnil Ravindranath 5730c20c4267SAnil Ravindranath fw_version = be16_to_cpu(pinstance->inq_data->fw_version); 5731c20c4267SAnil Ravindranath 573289a36810SAnil Ravindranath /* resource list is protected by pinstance->resource_lock. 573389a36810SAnil Ravindranath * init_res_table can be called from probe (user-thread) or runtime 573489a36810SAnil Ravindranath * reset (timer/tasklet) 573589a36810SAnil Ravindranath */ 573689a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->resource_lock, lock_flags); 573789a36810SAnil Ravindranath 573889a36810SAnil Ravindranath list_for_each_entry_safe(res, temp, &pinstance->used_res_q, queue) 573989a36810SAnil Ravindranath list_move_tail(&res->queue, &old_res); 574089a36810SAnil Ravindranath 574189a36810SAnil Ravindranath for (i = 0; i < pinstance->cfg_table->num_entries; i++) { 5742c20c4267SAnil Ravindranath if (be16_to_cpu(pinstance->inq_data->fw_version) <= 5743c20c4267SAnil Ravindranath PMCRAID_FW_VERSION_1) 574489a36810SAnil Ravindranath cfgte = &pinstance->cfg_table->entries[i]; 5745c20c4267SAnil Ravindranath else 5746c20c4267SAnil Ravindranath cfgte = (struct pmcraid_config_table_entry *) 5747c20c4267SAnil Ravindranath &pinstance->cfg_table->entries_ext[i]; 574889a36810SAnil Ravindranath 5749c20c4267SAnil Ravindranath if (!pmcraid_expose_resource(fw_version, cfgte)) 575089a36810SAnil Ravindranath continue; 575189a36810SAnil Ravindranath 575289a36810SAnil Ravindranath found = 0; 575389a36810SAnil Ravindranath 575489a36810SAnil Ravindranath /* If this entry was already detected and initialized */ 575589a36810SAnil Ravindranath list_for_each_entry_safe(res, temp, &old_res, queue) { 575689a36810SAnil Ravindranath 575789a36810SAnil Ravindranath rc = memcmp(&res->cfg_entry.resource_address, 575889a36810SAnil Ravindranath &cfgte->resource_address, 575989a36810SAnil Ravindranath sizeof(cfgte->resource_address)); 576089a36810SAnil Ravindranath if (!rc) { 576189a36810SAnil Ravindranath list_move_tail(&res->queue, 576289a36810SAnil Ravindranath &pinstance->used_res_q); 576389a36810SAnil Ravindranath found = 1; 576489a36810SAnil Ravindranath break; 576589a36810SAnil Ravindranath } 576689a36810SAnil Ravindranath } 576789a36810SAnil Ravindranath 576889a36810SAnil Ravindranath /* If this is new entry, initialize it and add it the queue */ 576989a36810SAnil Ravindranath if (!found) { 577089a36810SAnil Ravindranath 577189a36810SAnil Ravindranath if (list_empty(&pinstance->free_res_q)) { 577234876402SAnil Ravindranath pmcraid_err("Too many devices attached\n"); 577389a36810SAnil Ravindranath break; 577489a36810SAnil Ravindranath } 577589a36810SAnil Ravindranath 577689a36810SAnil Ravindranath found = 1; 577789a36810SAnil Ravindranath res = list_entry(pinstance->free_res_q.next, 577889a36810SAnil Ravindranath struct pmcraid_resource_entry, queue); 577989a36810SAnil Ravindranath 578089a36810SAnil Ravindranath res->scsi_dev = NULL; 578189a36810SAnil Ravindranath res->change_detected = RES_CHANGE_ADD; 578289a36810SAnil Ravindranath res->reset_progress = 0; 578389a36810SAnil Ravindranath list_move_tail(&res->queue, &pinstance->used_res_q); 578489a36810SAnil Ravindranath } 578589a36810SAnil Ravindranath 578689a36810SAnil Ravindranath /* copy new configuration table entry details into driver 578789a36810SAnil Ravindranath * maintained resource entry 578889a36810SAnil Ravindranath */ 578989a36810SAnil Ravindranath if (found) { 579089a36810SAnil Ravindranath memcpy(&res->cfg_entry, cfgte, 5791c20c4267SAnil Ravindranath pinstance->config_table_entry_size); 579289a36810SAnil Ravindranath pmcraid_info("New res type:%x, vset:%x, addr:%x:\n", 579389a36810SAnil Ravindranath res->cfg_entry.resource_type, 5794c20c4267SAnil Ravindranath (fw_version <= PMCRAID_FW_VERSION_1 ? 5795c20c4267SAnil Ravindranath res->cfg_entry.unique_flags1 : 5796c20c4267SAnil Ravindranath res->cfg_entry.array_id & 0xFF), 579789a36810SAnil Ravindranath le32_to_cpu(res->cfg_entry.resource_address)); 579889a36810SAnil Ravindranath } 579989a36810SAnil Ravindranath } 580089a36810SAnil Ravindranath 580189a36810SAnil Ravindranath /* Detect any deleted entries, mark them for deletion from mid-layer */ 580289a36810SAnil Ravindranath list_for_each_entry_safe(res, temp, &old_res, queue) { 580389a36810SAnil Ravindranath 580489a36810SAnil Ravindranath if (res->scsi_dev) { 580589a36810SAnil Ravindranath res->change_detected = RES_CHANGE_DEL; 580689a36810SAnil Ravindranath res->cfg_entry.resource_handle = 580789a36810SAnil Ravindranath PMCRAID_INVALID_RES_HANDLE; 580889a36810SAnil Ravindranath list_move_tail(&res->queue, &pinstance->used_res_q); 580989a36810SAnil Ravindranath } else { 581089a36810SAnil Ravindranath list_move_tail(&res->queue, &pinstance->free_res_q); 581189a36810SAnil Ravindranath } 581289a36810SAnil Ravindranath } 581389a36810SAnil Ravindranath 581489a36810SAnil Ravindranath /* release the resource list lock */ 581589a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); 5816592488a3SAnil Ravindranath pmcraid_set_timestamp(cmd); 581789a36810SAnil Ravindranath } 581889a36810SAnil Ravindranath 581989a36810SAnil Ravindranath /** 582089a36810SAnil Ravindranath * pmcraid_querycfg - Send a Query IOA Config to the adapter. 582189a36810SAnil Ravindranath * @cmd: pointer pmcraid_cmd struct 582289a36810SAnil Ravindranath * 582389a36810SAnil Ravindranath * This function sends a Query IOA Configuration command to the adapter to 582489a36810SAnil Ravindranath * retrieve the IOA configuration table. 582589a36810SAnil Ravindranath * 582689a36810SAnil Ravindranath * Return value: 582789a36810SAnil Ravindranath * none 582889a36810SAnil Ravindranath */ 582989a36810SAnil Ravindranath static void pmcraid_querycfg(struct pmcraid_cmd *cmd) 583089a36810SAnil Ravindranath { 583189a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 583289a36810SAnil Ravindranath struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; 583389a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 583489a36810SAnil Ravindranath int cfg_table_size = cpu_to_be32(sizeof(struct pmcraid_config_table)); 583589a36810SAnil Ravindranath 5836c20c4267SAnil Ravindranath if (be16_to_cpu(pinstance->inq_data->fw_version) <= 5837c20c4267SAnil Ravindranath PMCRAID_FW_VERSION_1) 5838c20c4267SAnil Ravindranath pinstance->config_table_entry_size = 5839c20c4267SAnil Ravindranath sizeof(struct pmcraid_config_table_entry); 5840c20c4267SAnil Ravindranath else 5841c20c4267SAnil Ravindranath pinstance->config_table_entry_size = 5842c20c4267SAnil Ravindranath sizeof(struct pmcraid_config_table_entry_ext); 5843c20c4267SAnil Ravindranath 584489a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_IOACMD; 584589a36810SAnil Ravindranath ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); 584689a36810SAnil Ravindranath 584789a36810SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_QUERY_IOA_CONFIG; 584889a36810SAnil Ravindranath 584989a36810SAnil Ravindranath /* firmware requires 4-byte length field, specified in B.E format */ 585089a36810SAnil Ravindranath memcpy(&(ioarcb->cdb[10]), &cfg_table_size, sizeof(cfg_table_size)); 585189a36810SAnil Ravindranath 585289a36810SAnil Ravindranath /* Since entire config table can be described by single IOADL, it can 585389a36810SAnil Ravindranath * be part of IOARCB itself 585489a36810SAnil Ravindranath */ 585589a36810SAnil Ravindranath ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + 585689a36810SAnil Ravindranath offsetof(struct pmcraid_ioarcb, 585789a36810SAnil Ravindranath add_data.u.ioadl[0])); 585889a36810SAnil Ravindranath ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); 585989a36810SAnil Ravindranath ioarcb->ioarcb_bus_addr &= ~(0x1FULL); 586089a36810SAnil Ravindranath 586189a36810SAnil Ravindranath ioarcb->request_flags0 |= NO_LINK_DESCS; 586289a36810SAnil Ravindranath ioarcb->data_transfer_length = 586389a36810SAnil Ravindranath cpu_to_le32(sizeof(struct pmcraid_config_table)); 586489a36810SAnil Ravindranath 586589a36810SAnil Ravindranath ioadl = &(ioarcb->add_data.u.ioadl[0]); 586688197966SAnil Ravindranath ioadl->flags = IOADL_FLAGS_LAST_DESC; 586789a36810SAnil Ravindranath ioadl->address = cpu_to_le64(pinstance->cfg_table_bus_addr); 586889a36810SAnil Ravindranath ioadl->data_len = cpu_to_le32(sizeof(struct pmcraid_config_table)); 586989a36810SAnil Ravindranath 587089a36810SAnil Ravindranath pmcraid_send_cmd(cmd, pmcraid_init_res_table, 587189a36810SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler); 587289a36810SAnil Ravindranath } 587389a36810SAnil Ravindranath 587489a36810SAnil Ravindranath 587589a36810SAnil Ravindranath /** 5876c20c4267SAnil Ravindranath * pmcraid_probe - PCI probe entry pointer for PMC MaxRAID controller driver 587789a36810SAnil Ravindranath * @pdev: pointer to pci device structure 587889a36810SAnil Ravindranath * @dev_id: pointer to device ids structure 587989a36810SAnil Ravindranath * 588089a36810SAnil Ravindranath * Return Value 588189a36810SAnil Ravindranath * returns 0 if the device is claimed and successfully configured. 588289a36810SAnil Ravindranath * returns non-zero error code in case of any failure 588389a36810SAnil Ravindranath */ 588489a36810SAnil Ravindranath static int __devinit pmcraid_probe( 588589a36810SAnil Ravindranath struct pci_dev *pdev, 588689a36810SAnil Ravindranath const struct pci_device_id *dev_id 588789a36810SAnil Ravindranath ) 588889a36810SAnil Ravindranath { 588989a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 589089a36810SAnil Ravindranath struct Scsi_Host *host; 589189a36810SAnil Ravindranath void __iomem *mapped_pci_addr; 589289a36810SAnil Ravindranath int rc = PCIBIOS_SUCCESSFUL; 589389a36810SAnil Ravindranath 589489a36810SAnil Ravindranath if (atomic_read(&pmcraid_adapter_count) >= PMCRAID_MAX_ADAPTERS) { 589589a36810SAnil Ravindranath pmcraid_err 589689a36810SAnil Ravindranath ("maximum number(%d) of supported adapters reached\n", 589789a36810SAnil Ravindranath atomic_read(&pmcraid_adapter_count)); 589889a36810SAnil Ravindranath return -ENOMEM; 589989a36810SAnil Ravindranath } 590089a36810SAnil Ravindranath 590189a36810SAnil Ravindranath atomic_inc(&pmcraid_adapter_count); 590289a36810SAnil Ravindranath rc = pci_enable_device(pdev); 590389a36810SAnil Ravindranath 590489a36810SAnil Ravindranath if (rc) { 590589a36810SAnil Ravindranath dev_err(&pdev->dev, "Cannot enable adapter\n"); 590689a36810SAnil Ravindranath atomic_dec(&pmcraid_adapter_count); 590789a36810SAnil Ravindranath return rc; 590889a36810SAnil Ravindranath } 590989a36810SAnil Ravindranath 591089a36810SAnil Ravindranath dev_info(&pdev->dev, 591189a36810SAnil Ravindranath "Found new IOA(%x:%x), Total IOA count: %d\n", 591289a36810SAnil Ravindranath pdev->vendor, pdev->device, 591389a36810SAnil Ravindranath atomic_read(&pmcraid_adapter_count)); 591489a36810SAnil Ravindranath 591589a36810SAnil Ravindranath rc = pci_request_regions(pdev, PMCRAID_DRIVER_NAME); 591689a36810SAnil Ravindranath 591789a36810SAnil Ravindranath if (rc < 0) { 591889a36810SAnil Ravindranath dev_err(&pdev->dev, 591989a36810SAnil Ravindranath "Couldn't register memory range of registers\n"); 592089a36810SAnil Ravindranath goto out_disable_device; 592189a36810SAnil Ravindranath } 592289a36810SAnil Ravindranath 592389a36810SAnil Ravindranath mapped_pci_addr = pci_iomap(pdev, 0, 0); 592489a36810SAnil Ravindranath 592589a36810SAnil Ravindranath if (!mapped_pci_addr) { 592689a36810SAnil Ravindranath dev_err(&pdev->dev, "Couldn't map PCI registers memory\n"); 592789a36810SAnil Ravindranath rc = -ENOMEM; 592889a36810SAnil Ravindranath goto out_release_regions; 592989a36810SAnil Ravindranath } 593089a36810SAnil Ravindranath 593189a36810SAnil Ravindranath pci_set_master(pdev); 593289a36810SAnil Ravindranath 593389a36810SAnil Ravindranath /* Firmware requires the system bus address of IOARCB to be within 593489a36810SAnil Ravindranath * 32-bit addressable range though it has 64-bit IOARRIN register. 593589a36810SAnil Ravindranath * However, firmware supports 64-bit streaming DMA buffers, whereas 593689a36810SAnil Ravindranath * coherent buffers are to be 32-bit. Since pci_alloc_consistent always 593789a36810SAnil Ravindranath * returns memory within 4GB (if not, change this logic), coherent 593825985edcSLucas De Marchi * buffers are within firmware acceptable address ranges. 593989a36810SAnil Ravindranath */ 594089a36810SAnil Ravindranath if ((sizeof(dma_addr_t) == 4) || 594189a36810SAnil Ravindranath pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) 594289a36810SAnil Ravindranath rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 594389a36810SAnil Ravindranath 594489a36810SAnil Ravindranath /* firmware expects 32-bit DMA addresses for IOARRIN register; set 32 594589a36810SAnil Ravindranath * bit mask for pci_alloc_consistent to return addresses within 4GB 594689a36810SAnil Ravindranath */ 594789a36810SAnil Ravindranath if (rc == 0) 594889a36810SAnil Ravindranath rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); 594989a36810SAnil Ravindranath 595089a36810SAnil Ravindranath if (rc != 0) { 595189a36810SAnil Ravindranath dev_err(&pdev->dev, "Failed to set PCI DMA mask\n"); 595289a36810SAnil Ravindranath goto cleanup_nomem; 595389a36810SAnil Ravindranath } 595489a36810SAnil Ravindranath 595589a36810SAnil Ravindranath host = scsi_host_alloc(&pmcraid_host_template, 595689a36810SAnil Ravindranath sizeof(struct pmcraid_instance)); 595789a36810SAnil Ravindranath 595889a36810SAnil Ravindranath if (!host) { 595989a36810SAnil Ravindranath dev_err(&pdev->dev, "scsi_host_alloc failed!\n"); 596089a36810SAnil Ravindranath rc = -ENOMEM; 596189a36810SAnil Ravindranath goto cleanup_nomem; 596289a36810SAnil Ravindranath } 596389a36810SAnil Ravindranath 596489a36810SAnil Ravindranath host->max_id = PMCRAID_MAX_NUM_TARGETS_PER_BUS; 596589a36810SAnil Ravindranath host->max_lun = PMCRAID_MAX_NUM_LUNS_PER_TARGET; 596689a36810SAnil Ravindranath host->unique_id = host->host_no; 596789a36810SAnil Ravindranath host->max_channel = PMCRAID_MAX_BUS_TO_SCAN; 596889a36810SAnil Ravindranath host->max_cmd_len = PMCRAID_MAX_CDB_LEN; 596989a36810SAnil Ravindranath 597089a36810SAnil Ravindranath /* zero out entire instance structure */ 597189a36810SAnil Ravindranath pinstance = (struct pmcraid_instance *)host->hostdata; 597289a36810SAnil Ravindranath memset(pinstance, 0, sizeof(*pinstance)); 597389a36810SAnil Ravindranath 597489a36810SAnil Ravindranath pinstance->chip_cfg = 597589a36810SAnil Ravindranath (struct pmcraid_chip_details *)(dev_id->driver_data); 597689a36810SAnil Ravindranath 597789a36810SAnil Ravindranath rc = pmcraid_init_instance(pdev, host, mapped_pci_addr); 597889a36810SAnil Ravindranath 597989a36810SAnil Ravindranath if (rc < 0) { 598089a36810SAnil Ravindranath dev_err(&pdev->dev, "failed to initialize adapter instance\n"); 598189a36810SAnil Ravindranath goto out_scsi_host_put; 598289a36810SAnil Ravindranath } 598389a36810SAnil Ravindranath 598489a36810SAnil Ravindranath pci_set_drvdata(pdev, pinstance); 598589a36810SAnil Ravindranath 598689a36810SAnil Ravindranath /* Save PCI config-space for use following the reset */ 598789a36810SAnil Ravindranath rc = pci_save_state(pinstance->pdev); 598889a36810SAnil Ravindranath 598989a36810SAnil Ravindranath if (rc != 0) { 599089a36810SAnil Ravindranath dev_err(&pdev->dev, "Failed to save PCI config space\n"); 599189a36810SAnil Ravindranath goto out_scsi_host_put; 599289a36810SAnil Ravindranath } 599389a36810SAnil Ravindranath 599489a36810SAnil Ravindranath pmcraid_disable_interrupts(pinstance, ~0); 599589a36810SAnil Ravindranath 599689a36810SAnil Ravindranath rc = pmcraid_register_interrupt_handler(pinstance); 599789a36810SAnil Ravindranath 599889a36810SAnil Ravindranath if (rc) { 599934876402SAnil Ravindranath dev_err(&pdev->dev, "couldn't register interrupt handler\n"); 600089a36810SAnil Ravindranath goto out_scsi_host_put; 600189a36810SAnil Ravindranath } 600289a36810SAnil Ravindranath 600389a36810SAnil Ravindranath pmcraid_init_tasklets(pinstance); 600489a36810SAnil Ravindranath 600589a36810SAnil Ravindranath /* allocate verious buffers used by LLD.*/ 600689a36810SAnil Ravindranath rc = pmcraid_init_buffers(pinstance); 600789a36810SAnil Ravindranath 600889a36810SAnil Ravindranath if (rc) { 600989a36810SAnil Ravindranath pmcraid_err("couldn't allocate memory blocks\n"); 601089a36810SAnil Ravindranath goto out_unregister_isr; 601189a36810SAnil Ravindranath } 601289a36810SAnil Ravindranath 601389a36810SAnil Ravindranath /* check the reset type required */ 601489a36810SAnil Ravindranath pmcraid_reset_type(pinstance); 601589a36810SAnil Ravindranath 601689a36810SAnil Ravindranath pmcraid_enable_interrupts(pinstance, PMCRAID_PCI_INTERRUPTS); 601789a36810SAnil Ravindranath 601889a36810SAnil Ravindranath /* Start IOA firmware initialization and bring card to Operational 601989a36810SAnil Ravindranath * state. 602089a36810SAnil Ravindranath */ 602189a36810SAnil Ravindranath pmcraid_info("starting IOA initialization sequence\n"); 602289a36810SAnil Ravindranath if (pmcraid_reset_bringup(pinstance)) { 602334876402SAnil Ravindranath dev_err(&pdev->dev, "couldn't initialize IOA\n"); 602489a36810SAnil Ravindranath rc = 1; 602589a36810SAnil Ravindranath goto out_release_bufs; 602689a36810SAnil Ravindranath } 602789a36810SAnil Ravindranath 602889a36810SAnil Ravindranath /* Add adapter instance into mid-layer list */ 602989a36810SAnil Ravindranath rc = scsi_add_host(pinstance->host, &pdev->dev); 603089a36810SAnil Ravindranath if (rc != 0) { 603189a36810SAnil Ravindranath pmcraid_err("couldn't add host into mid-layer: %d\n", rc); 603289a36810SAnil Ravindranath goto out_release_bufs; 603389a36810SAnil Ravindranath } 603489a36810SAnil Ravindranath 603589a36810SAnil Ravindranath scsi_scan_host(pinstance->host); 603689a36810SAnil Ravindranath 603789a36810SAnil Ravindranath rc = pmcraid_setup_chrdev(pinstance); 603889a36810SAnil Ravindranath 603989a36810SAnil Ravindranath if (rc != 0) { 604089a36810SAnil Ravindranath pmcraid_err("couldn't create mgmt interface, error: %x\n", 604189a36810SAnil Ravindranath rc); 604289a36810SAnil Ravindranath goto out_remove_host; 604389a36810SAnil Ravindranath } 604489a36810SAnil Ravindranath 604589a36810SAnil Ravindranath /* Schedule worker thread to handle CCN and take care of adding and 604689a36810SAnil Ravindranath * removing devices to OS 604789a36810SAnil Ravindranath */ 604889a36810SAnil Ravindranath atomic_set(&pinstance->expose_resources, 1); 604989a36810SAnil Ravindranath schedule_work(&pinstance->worker_q); 605089a36810SAnil Ravindranath return rc; 605189a36810SAnil Ravindranath 605289a36810SAnil Ravindranath out_remove_host: 605389a36810SAnil Ravindranath scsi_remove_host(host); 605489a36810SAnil Ravindranath 605589a36810SAnil Ravindranath out_release_bufs: 605689a36810SAnil Ravindranath pmcraid_release_buffers(pinstance); 605789a36810SAnil Ravindranath 605889a36810SAnil Ravindranath out_unregister_isr: 605989a36810SAnil Ravindranath pmcraid_kill_tasklets(pinstance); 606089a36810SAnil Ravindranath pmcraid_unregister_interrupt_handler(pinstance); 606189a36810SAnil Ravindranath 606289a36810SAnil Ravindranath out_scsi_host_put: 606389a36810SAnil Ravindranath scsi_host_put(host); 606489a36810SAnil Ravindranath 606589a36810SAnil Ravindranath cleanup_nomem: 606689a36810SAnil Ravindranath iounmap(mapped_pci_addr); 606789a36810SAnil Ravindranath 606889a36810SAnil Ravindranath out_release_regions: 606989a36810SAnil Ravindranath pci_release_regions(pdev); 607089a36810SAnil Ravindranath 607189a36810SAnil Ravindranath out_disable_device: 607289a36810SAnil Ravindranath atomic_dec(&pmcraid_adapter_count); 607389a36810SAnil Ravindranath pci_set_drvdata(pdev, NULL); 607489a36810SAnil Ravindranath pci_disable_device(pdev); 607589a36810SAnil Ravindranath return -ENODEV; 607689a36810SAnil Ravindranath } 607789a36810SAnil Ravindranath 607889a36810SAnil Ravindranath /* 607989a36810SAnil Ravindranath * PCI driver structure of pcmraid driver 608089a36810SAnil Ravindranath */ 608189a36810SAnil Ravindranath static struct pci_driver pmcraid_driver = { 608289a36810SAnil Ravindranath .name = PMCRAID_DRIVER_NAME, 608389a36810SAnil Ravindranath .id_table = pmcraid_pci_table, 608489a36810SAnil Ravindranath .probe = pmcraid_probe, 608589a36810SAnil Ravindranath .remove = pmcraid_remove, 608689a36810SAnil Ravindranath .suspend = pmcraid_suspend, 608789a36810SAnil Ravindranath .resume = pmcraid_resume, 608889a36810SAnil Ravindranath .shutdown = pmcraid_shutdown 608989a36810SAnil Ravindranath }; 609089a36810SAnil Ravindranath 609189a36810SAnil Ravindranath /** 609289a36810SAnil Ravindranath * pmcraid_init - module load entry point 609389a36810SAnil Ravindranath */ 609489a36810SAnil Ravindranath static int __init pmcraid_init(void) 609589a36810SAnil Ravindranath { 609689a36810SAnil Ravindranath dev_t dev; 609789a36810SAnil Ravindranath int error; 609889a36810SAnil Ravindranath 609989a36810SAnil Ravindranath pmcraid_info("%s Device Driver version: %s %s\n", 610089a36810SAnil Ravindranath PMCRAID_DRIVER_NAME, 610189a36810SAnil Ravindranath PMCRAID_DRIVER_VERSION, PMCRAID_DRIVER_DATE); 610289a36810SAnil Ravindranath 610389a36810SAnil Ravindranath error = alloc_chrdev_region(&dev, 0, 610489a36810SAnil Ravindranath PMCRAID_MAX_ADAPTERS, 610589a36810SAnil Ravindranath PMCRAID_DEVFILE); 610689a36810SAnil Ravindranath 610789a36810SAnil Ravindranath if (error) { 610889a36810SAnil Ravindranath pmcraid_err("failed to get a major number for adapters\n"); 610989a36810SAnil Ravindranath goto out_init; 611089a36810SAnil Ravindranath } 611189a36810SAnil Ravindranath 611289a36810SAnil Ravindranath pmcraid_major = MAJOR(dev); 611389a36810SAnil Ravindranath pmcraid_class = class_create(THIS_MODULE, PMCRAID_DEVFILE); 611489a36810SAnil Ravindranath 611589a36810SAnil Ravindranath if (IS_ERR(pmcraid_class)) { 611689a36810SAnil Ravindranath error = PTR_ERR(pmcraid_class); 611789a36810SAnil Ravindranath pmcraid_err("failed to register with with sysfs, error = %x\n", 611889a36810SAnil Ravindranath error); 611989a36810SAnil Ravindranath goto out_unreg_chrdev; 612089a36810SAnil Ravindranath } 612189a36810SAnil Ravindranath 612289a36810SAnil Ravindranath error = pmcraid_netlink_init(); 612389a36810SAnil Ravindranath 612489a36810SAnil Ravindranath if (error) 612589a36810SAnil Ravindranath goto out_unreg_chrdev; 612689a36810SAnil Ravindranath 612789a36810SAnil Ravindranath error = pci_register_driver(&pmcraid_driver); 612889a36810SAnil Ravindranath 612989a36810SAnil Ravindranath if (error == 0) 613089a36810SAnil Ravindranath goto out_init; 613189a36810SAnil Ravindranath 613289a36810SAnil Ravindranath pmcraid_err("failed to register pmcraid driver, error = %x\n", 613389a36810SAnil Ravindranath error); 613489a36810SAnil Ravindranath class_destroy(pmcraid_class); 613589a36810SAnil Ravindranath pmcraid_netlink_release(); 613689a36810SAnil Ravindranath 613789a36810SAnil Ravindranath out_unreg_chrdev: 613889a36810SAnil Ravindranath unregister_chrdev_region(MKDEV(pmcraid_major, 0), PMCRAID_MAX_ADAPTERS); 613934876402SAnil Ravindranath 614089a36810SAnil Ravindranath out_init: 614189a36810SAnil Ravindranath return error; 614289a36810SAnil Ravindranath } 614389a36810SAnil Ravindranath 614489a36810SAnil Ravindranath /** 614589a36810SAnil Ravindranath * pmcraid_exit - module unload entry point 614689a36810SAnil Ravindranath */ 614789a36810SAnil Ravindranath static void __exit pmcraid_exit(void) 614889a36810SAnil Ravindranath { 614989a36810SAnil Ravindranath pmcraid_netlink_release(); 615089a36810SAnil Ravindranath unregister_chrdev_region(MKDEV(pmcraid_major, 0), 615189a36810SAnil Ravindranath PMCRAID_MAX_ADAPTERS); 615289a36810SAnil Ravindranath pci_unregister_driver(&pmcraid_driver); 6153592488a3SAnil Ravindranath class_destroy(pmcraid_class); 615489a36810SAnil Ravindranath } 615589a36810SAnil Ravindranath 615689a36810SAnil Ravindranath module_init(pmcraid_init); 615789a36810SAnil Ravindranath module_exit(pmcraid_exit); 6158