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