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 */ 12889a36810SAnil Ravindranath static struct pci_device_id pmcraid_pci_table[] __devinitdata = { 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 140789a36810SAnil Ravindranath static struct genl_family pmcraid_event_family = { 140889a36810SAnil Ravindranath .id = GENL_ID_GENERATE, 140989a36810SAnil Ravindranath .name = "pmcraid", 141089a36810SAnil Ravindranath .version = 1, 141189a36810SAnil Ravindranath .maxattr = PMCRAID_AEN_ATTR_MAX 141289a36810SAnil Ravindranath }; 141389a36810SAnil Ravindranath 141489a36810SAnil Ravindranath /** 141589a36810SAnil Ravindranath * pmcraid_netlink_init - registers pmcraid_event_family 141689a36810SAnil Ravindranath * 141789a36810SAnil Ravindranath * Return value: 141889a36810SAnil Ravindranath * 0 if the pmcraid_event_family is successfully registered 141989a36810SAnil Ravindranath * with netlink generic, non-zero otherwise 142089a36810SAnil Ravindranath */ 142189a36810SAnil Ravindranath static int pmcraid_netlink_init(void) 142289a36810SAnil Ravindranath { 142389a36810SAnil Ravindranath int result; 142489a36810SAnil Ravindranath 142589a36810SAnil Ravindranath result = genl_register_family(&pmcraid_event_family); 142689a36810SAnil Ravindranath 142789a36810SAnil Ravindranath if (result) 142889a36810SAnil Ravindranath return result; 142989a36810SAnil Ravindranath 143089a36810SAnil Ravindranath pmcraid_info("registered NETLINK GENERIC group: %d\n", 143189a36810SAnil Ravindranath pmcraid_event_family.id); 143289a36810SAnil Ravindranath 143389a36810SAnil Ravindranath return result; 143489a36810SAnil Ravindranath } 143589a36810SAnil Ravindranath 143689a36810SAnil Ravindranath /** 143789a36810SAnil Ravindranath * pmcraid_netlink_release - unregisters pmcraid_event_family 143889a36810SAnil Ravindranath * 143989a36810SAnil Ravindranath * Return value: 144089a36810SAnil Ravindranath * none 144189a36810SAnil Ravindranath */ 144289a36810SAnil Ravindranath static void pmcraid_netlink_release(void) 144389a36810SAnil Ravindranath { 144489a36810SAnil Ravindranath genl_unregister_family(&pmcraid_event_family); 144589a36810SAnil Ravindranath } 144689a36810SAnil Ravindranath 144789a36810SAnil Ravindranath /** 144889a36810SAnil Ravindranath * pmcraid_notify_aen - sends event msg to user space application 144989a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 145089a36810SAnil Ravindranath * @type: HCAM type 145189a36810SAnil Ravindranath * 145289a36810SAnil Ravindranath * Return value: 145389a36810SAnil Ravindranath * 0 if success, error value in case of any failure. 145489a36810SAnil Ravindranath */ 1455c20c4267SAnil Ravindranath static int pmcraid_notify_aen( 1456c20c4267SAnil Ravindranath struct pmcraid_instance *pinstance, 1457c20c4267SAnil Ravindranath struct pmcraid_aen_msg *aen_msg, 1458c20c4267SAnil Ravindranath u32 data_size 1459c20c4267SAnil Ravindranath ) 146089a36810SAnil Ravindranath { 146189a36810SAnil Ravindranath struct sk_buff *skb; 146289a36810SAnil Ravindranath void *msg_header; 1463c20c4267SAnil Ravindranath u32 total_size, nla_genl_hdr_total_size; 146489a36810SAnil Ravindranath int result; 146589a36810SAnil Ravindranath 146689a36810SAnil Ravindranath aen_msg->hostno = (pinstance->host->unique_id << 16 | 146789a36810SAnil Ravindranath MINOR(pinstance->cdev.dev)); 146889a36810SAnil Ravindranath aen_msg->length = data_size; 1469c20c4267SAnil Ravindranath 147089a36810SAnil Ravindranath data_size += sizeof(*aen_msg); 147189a36810SAnil Ravindranath 147289a36810SAnil Ravindranath total_size = nla_total_size(data_size); 1473c20c4267SAnil Ravindranath /* Add GENL_HDR to total_size */ 1474c20c4267SAnil Ravindranath nla_genl_hdr_total_size = 1475c20c4267SAnil Ravindranath (total_size + (GENL_HDRLEN + 1476c20c4267SAnil Ravindranath ((struct genl_family *)&pmcraid_event_family)->hdrsize) 1477c20c4267SAnil Ravindranath + NLMSG_HDRLEN); 1478c20c4267SAnil Ravindranath skb = genlmsg_new(nla_genl_hdr_total_size, GFP_ATOMIC); 147989a36810SAnil Ravindranath 148089a36810SAnil Ravindranath 148189a36810SAnil Ravindranath if (!skb) { 148289a36810SAnil Ravindranath pmcraid_err("Failed to allocate aen data SKB of size: %x\n", 148389a36810SAnil Ravindranath total_size); 148489a36810SAnil Ravindranath return -ENOMEM; 148589a36810SAnil Ravindranath } 148689a36810SAnil Ravindranath 148789a36810SAnil Ravindranath /* add the genetlink message header */ 148889a36810SAnil Ravindranath msg_header = genlmsg_put(skb, 0, 0, 148989a36810SAnil Ravindranath &pmcraid_event_family, 0, 149089a36810SAnil Ravindranath PMCRAID_AEN_CMD_EVENT); 149189a36810SAnil Ravindranath if (!msg_header) { 149289a36810SAnil Ravindranath pmcraid_err("failed to copy command details\n"); 149389a36810SAnil Ravindranath nlmsg_free(skb); 149489a36810SAnil Ravindranath return -ENOMEM; 149589a36810SAnil Ravindranath } 149689a36810SAnil Ravindranath 149789a36810SAnil Ravindranath result = nla_put(skb, PMCRAID_AEN_ATTR_EVENT, data_size, aen_msg); 149889a36810SAnil Ravindranath 149989a36810SAnil Ravindranath if (result) { 150089a36810SAnil Ravindranath pmcraid_err("failed to copy AEN attribute data\n"); 150189a36810SAnil Ravindranath nlmsg_free(skb); 150289a36810SAnil Ravindranath return -EINVAL; 150389a36810SAnil Ravindranath } 150489a36810SAnil Ravindranath 150589a36810SAnil Ravindranath /* send genetlink multicast message to notify appplications */ 150689a36810SAnil Ravindranath result = genlmsg_end(skb, msg_header); 150789a36810SAnil Ravindranath 150889a36810SAnil Ravindranath if (result < 0) { 150989a36810SAnil Ravindranath pmcraid_err("genlmsg_end failed\n"); 151089a36810SAnil Ravindranath nlmsg_free(skb); 151189a36810SAnil Ravindranath return result; 151289a36810SAnil Ravindranath } 151389a36810SAnil Ravindranath 151489a36810SAnil Ravindranath result = 151589a36810SAnil Ravindranath genlmsg_multicast(skb, 0, pmcraid_event_family.id, GFP_ATOMIC); 151689a36810SAnil Ravindranath 151789a36810SAnil Ravindranath /* If there are no listeners, genlmsg_multicast may return non-zero 151889a36810SAnil Ravindranath * value. 151989a36810SAnil Ravindranath */ 152089a36810SAnil Ravindranath if (result) 1521c20c4267SAnil Ravindranath pmcraid_info("error (%x) sending aen event message\n", result); 152289a36810SAnil Ravindranath return result; 152389a36810SAnil Ravindranath } 152489a36810SAnil Ravindranath 152589a36810SAnil Ravindranath /** 1526c20c4267SAnil Ravindranath * pmcraid_notify_ccn - notifies about CCN event msg to user space 1527c20c4267SAnil Ravindranath * @pinstance: pointer adapter instance structure 1528c20c4267SAnil Ravindranath * 1529c20c4267SAnil Ravindranath * Return value: 1530c20c4267SAnil Ravindranath * 0 if success, error value in case of any failure 1531c20c4267SAnil Ravindranath */ 1532c20c4267SAnil Ravindranath static int pmcraid_notify_ccn(struct pmcraid_instance *pinstance) 1533c20c4267SAnil Ravindranath { 1534c20c4267SAnil Ravindranath return pmcraid_notify_aen(pinstance, 1535c20c4267SAnil Ravindranath pinstance->ccn.msg, 1536c20c4267SAnil Ravindranath pinstance->ccn.hcam->data_len + 1537c20c4267SAnil Ravindranath sizeof(struct pmcraid_hcam_hdr)); 1538c20c4267SAnil Ravindranath } 1539c20c4267SAnil Ravindranath 1540c20c4267SAnil Ravindranath /** 1541c20c4267SAnil Ravindranath * pmcraid_notify_ldn - notifies about CCN event msg to user space 1542c20c4267SAnil Ravindranath * @pinstance: pointer adapter instance structure 1543c20c4267SAnil Ravindranath * 1544c20c4267SAnil Ravindranath * Return value: 1545c20c4267SAnil Ravindranath * 0 if success, error value in case of any failure 1546c20c4267SAnil Ravindranath */ 1547c20c4267SAnil Ravindranath static int pmcraid_notify_ldn(struct pmcraid_instance *pinstance) 1548c20c4267SAnil Ravindranath { 1549c20c4267SAnil Ravindranath return pmcraid_notify_aen(pinstance, 1550c20c4267SAnil Ravindranath pinstance->ldn.msg, 1551c20c4267SAnil Ravindranath pinstance->ldn.hcam->data_len + 1552c20c4267SAnil Ravindranath sizeof(struct pmcraid_hcam_hdr)); 1553c20c4267SAnil Ravindranath } 1554c20c4267SAnil Ravindranath 1555c20c4267SAnil Ravindranath /** 1556c20c4267SAnil Ravindranath * pmcraid_notify_ioastate - sends IOA state event msg to user space 1557c20c4267SAnil Ravindranath * @pinstance: pointer adapter instance structure 1558c20c4267SAnil Ravindranath * @evt: controller state event to be sent 1559c20c4267SAnil Ravindranath * 1560c20c4267SAnil Ravindranath * Return value: 1561c20c4267SAnil Ravindranath * 0 if success, error value in case of any failure 1562c20c4267SAnil Ravindranath */ 1563c20c4267SAnil Ravindranath static void pmcraid_notify_ioastate(struct pmcraid_instance *pinstance, u32 evt) 1564c20c4267SAnil Ravindranath { 1565c20c4267SAnil Ravindranath pinstance->scn.ioa_state = evt; 1566c20c4267SAnil Ravindranath pmcraid_notify_aen(pinstance, 1567c20c4267SAnil Ravindranath &pinstance->scn.msg, 1568c20c4267SAnil Ravindranath sizeof(u32)); 1569c20c4267SAnil Ravindranath } 1570c20c4267SAnil Ravindranath 1571c20c4267SAnil Ravindranath /** 157289a36810SAnil Ravindranath * pmcraid_handle_config_change - Handle a config change from the adapter 157389a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 157489a36810SAnil Ravindranath * 157589a36810SAnil Ravindranath * Return value: 157689a36810SAnil Ravindranath * none 157789a36810SAnil Ravindranath */ 1578729c8456SAnil Ravindranath 157989a36810SAnil Ravindranath static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance) 158089a36810SAnil Ravindranath { 158189a36810SAnil Ravindranath struct pmcraid_config_table_entry *cfg_entry; 158289a36810SAnil Ravindranath struct pmcraid_hcam_ccn *ccn_hcam; 158389a36810SAnil Ravindranath struct pmcraid_cmd *cmd; 158489a36810SAnil Ravindranath struct pmcraid_cmd *cfgcmd; 158589a36810SAnil Ravindranath struct pmcraid_resource_entry *res = NULL; 158689a36810SAnil Ravindranath unsigned long lock_flags; 158789a36810SAnil Ravindranath unsigned long host_lock_flags; 1588729c8456SAnil Ravindranath u32 new_entry = 1; 1589729c8456SAnil Ravindranath u32 hidden_entry = 0; 1590c20c4267SAnil Ravindranath u16 fw_version; 159189a36810SAnil Ravindranath int rc; 159289a36810SAnil Ravindranath 159389a36810SAnil Ravindranath ccn_hcam = (struct pmcraid_hcam_ccn *)pinstance->ccn.hcam; 159489a36810SAnil Ravindranath cfg_entry = &ccn_hcam->cfg_entry; 1595c20c4267SAnil Ravindranath fw_version = be16_to_cpu(pinstance->inq_data->fw_version); 159689a36810SAnil Ravindranath 1597592488a3SAnil Ravindranath pmcraid_info("CCN(%x): %x timestamp: %llx type: %x lost: %x flags: %x \ 1598592488a3SAnil Ravindranath res: %x:%x:%x:%x\n", 159989a36810SAnil Ravindranath pinstance->ccn.hcam->ilid, 160089a36810SAnil Ravindranath pinstance->ccn.hcam->op_code, 1601592488a3SAnil Ravindranath ((pinstance->ccn.hcam->timestamp1) | 1602592488a3SAnil Ravindranath ((pinstance->ccn.hcam->timestamp2 & 0xffffffffLL) << 32)), 160389a36810SAnil Ravindranath pinstance->ccn.hcam->notification_type, 160489a36810SAnil Ravindranath pinstance->ccn.hcam->notification_lost, 160589a36810SAnil Ravindranath pinstance->ccn.hcam->flags, 160689a36810SAnil Ravindranath pinstance->host->unique_id, 160789a36810SAnil Ravindranath RES_IS_VSET(*cfg_entry) ? PMCRAID_VSET_BUS_ID : 160889a36810SAnil Ravindranath (RES_IS_GSCSI(*cfg_entry) ? PMCRAID_PHYS_BUS_ID : 160989a36810SAnil Ravindranath RES_BUS(cfg_entry->resource_address)), 1610c20c4267SAnil Ravindranath RES_IS_VSET(*cfg_entry) ? 1611c20c4267SAnil Ravindranath (fw_version <= PMCRAID_FW_VERSION_1 ? 1612c20c4267SAnil Ravindranath cfg_entry->unique_flags1 : 1613c20c4267SAnil Ravindranath cfg_entry->array_id & 0xFF) : 161489a36810SAnil Ravindranath RES_TARGET(cfg_entry->resource_address), 161589a36810SAnil Ravindranath RES_LUN(cfg_entry->resource_address)); 161689a36810SAnil Ravindranath 161789a36810SAnil Ravindranath 161889a36810SAnil Ravindranath /* If this HCAM indicates a lost notification, read the config table */ 161989a36810SAnil Ravindranath if (pinstance->ccn.hcam->notification_lost) { 162089a36810SAnil Ravindranath cfgcmd = pmcraid_get_free_cmd(pinstance); 162189a36810SAnil Ravindranath if (cfgcmd) { 162289a36810SAnil Ravindranath pmcraid_info("lost CCN, reading config table\b"); 162389a36810SAnil Ravindranath pinstance->reinit_cfg_table = 1; 162489a36810SAnil Ravindranath pmcraid_querycfg(cfgcmd); 162589a36810SAnil Ravindranath } else { 162689a36810SAnil Ravindranath pmcraid_err("lost CCN, no free cmd for querycfg\n"); 162789a36810SAnil Ravindranath } 162889a36810SAnil Ravindranath goto out_notify_apps; 162989a36810SAnil Ravindranath } 163089a36810SAnil Ravindranath 163189a36810SAnil Ravindranath /* If this resource is not going to be added to mid-layer, just notify 1632729c8456SAnil Ravindranath * applications and return. If this notification is about hiding a VSET 1633729c8456SAnil Ravindranath * resource, check if it was exposed already. 163489a36810SAnil Ravindranath */ 1635729c8456SAnil Ravindranath if (pinstance->ccn.hcam->notification_type == 1636729c8456SAnil Ravindranath NOTIFICATION_TYPE_ENTRY_CHANGED && 1637c20c4267SAnil Ravindranath cfg_entry->resource_type == RES_TYPE_VSET) { 1638c20c4267SAnil Ravindranath 1639c20c4267SAnil Ravindranath if (fw_version <= PMCRAID_FW_VERSION_1) 1640c20c4267SAnil Ravindranath hidden_entry = (cfg_entry->unique_flags1 & 0x80) != 0; 1641c20c4267SAnil Ravindranath else 1642c20c4267SAnil Ravindranath hidden_entry = (cfg_entry->unique_flags1 & 0x80) != 0; 1643c20c4267SAnil Ravindranath 1644c20c4267SAnil Ravindranath } else if (!pmcraid_expose_resource(fw_version, cfg_entry)) { 164589a36810SAnil Ravindranath goto out_notify_apps; 1646c20c4267SAnil Ravindranath } 164789a36810SAnil Ravindranath 164889a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->resource_lock, lock_flags); 164989a36810SAnil Ravindranath list_for_each_entry(res, &pinstance->used_res_q, queue) { 165089a36810SAnil Ravindranath rc = memcmp(&res->cfg_entry.resource_address, 165189a36810SAnil Ravindranath &cfg_entry->resource_address, 165289a36810SAnil Ravindranath sizeof(cfg_entry->resource_address)); 165389a36810SAnil Ravindranath if (!rc) { 165489a36810SAnil Ravindranath new_entry = 0; 165589a36810SAnil Ravindranath break; 165689a36810SAnil Ravindranath } 165789a36810SAnil Ravindranath } 165889a36810SAnil Ravindranath 165989a36810SAnil Ravindranath if (new_entry) { 166089a36810SAnil Ravindranath 1661729c8456SAnil Ravindranath if (hidden_entry) { 1662729c8456SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, 1663729c8456SAnil Ravindranath lock_flags); 1664729c8456SAnil Ravindranath goto out_notify_apps; 1665729c8456SAnil Ravindranath } 1666729c8456SAnil Ravindranath 166789a36810SAnil Ravindranath /* If there are more number of resources than what driver can 166889a36810SAnil Ravindranath * manage, do not notify the applications about the CCN. Just 166989a36810SAnil Ravindranath * ignore this notifications and re-register the same HCAM 167089a36810SAnil Ravindranath */ 167189a36810SAnil Ravindranath if (list_empty(&pinstance->free_res_q)) { 167289a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, 167389a36810SAnil Ravindranath lock_flags); 167489a36810SAnil Ravindranath pmcraid_err("too many resources attached\n"); 167589a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, 167689a36810SAnil Ravindranath host_lock_flags); 167789a36810SAnil Ravindranath pmcraid_send_hcam(pinstance, 167889a36810SAnil Ravindranath PMCRAID_HCAM_CODE_CONFIG_CHANGE); 167989a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 168089a36810SAnil Ravindranath host_lock_flags); 168189a36810SAnil Ravindranath return; 168289a36810SAnil Ravindranath } 168389a36810SAnil Ravindranath 168489a36810SAnil Ravindranath res = list_entry(pinstance->free_res_q.next, 168589a36810SAnil Ravindranath struct pmcraid_resource_entry, queue); 168689a36810SAnil Ravindranath 168789a36810SAnil Ravindranath list_del(&res->queue); 168889a36810SAnil Ravindranath res->scsi_dev = NULL; 168989a36810SAnil Ravindranath res->reset_progress = 0; 169089a36810SAnil Ravindranath list_add_tail(&res->queue, &pinstance->used_res_q); 169189a36810SAnil Ravindranath } 169289a36810SAnil Ravindranath 1693c20c4267SAnil Ravindranath memcpy(&res->cfg_entry, cfg_entry, pinstance->config_table_entry_size); 169489a36810SAnil Ravindranath 169589a36810SAnil Ravindranath if (pinstance->ccn.hcam->notification_type == 1696729c8456SAnil Ravindranath NOTIFICATION_TYPE_ENTRY_DELETED || hidden_entry) { 169789a36810SAnil Ravindranath if (res->scsi_dev) { 1698c20c4267SAnil Ravindranath if (fw_version <= PMCRAID_FW_VERSION_1) 1699729c8456SAnil Ravindranath res->cfg_entry.unique_flags1 &= 0x7F; 1700c20c4267SAnil Ravindranath else 1701c20c4267SAnil Ravindranath res->cfg_entry.array_id &= 0xFF; 170289a36810SAnil Ravindranath res->change_detected = RES_CHANGE_DEL; 170389a36810SAnil Ravindranath res->cfg_entry.resource_handle = 170489a36810SAnil Ravindranath PMCRAID_INVALID_RES_HANDLE; 170589a36810SAnil Ravindranath schedule_work(&pinstance->worker_q); 170689a36810SAnil Ravindranath } else { 170789a36810SAnil Ravindranath /* This may be one of the non-exposed resources */ 170889a36810SAnil Ravindranath list_move_tail(&res->queue, &pinstance->free_res_q); 170989a36810SAnil Ravindranath } 171089a36810SAnil Ravindranath } else if (!res->scsi_dev) { 171189a36810SAnil Ravindranath res->change_detected = RES_CHANGE_ADD; 171289a36810SAnil Ravindranath schedule_work(&pinstance->worker_q); 171389a36810SAnil Ravindranath } 171489a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); 171589a36810SAnil Ravindranath 171689a36810SAnil Ravindranath out_notify_apps: 171789a36810SAnil Ravindranath 171889a36810SAnil Ravindranath /* Notify configuration changes to registered applications.*/ 171989a36810SAnil Ravindranath if (!pmcraid_disable_aen) 1720c20c4267SAnil Ravindranath pmcraid_notify_ccn(pinstance); 172189a36810SAnil Ravindranath 172289a36810SAnil Ravindranath cmd = pmcraid_init_hcam(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE); 172389a36810SAnil Ravindranath if (cmd) 172489a36810SAnil Ravindranath pmcraid_send_hcam_cmd(cmd); 172589a36810SAnil Ravindranath } 172689a36810SAnil Ravindranath 172789a36810SAnil Ravindranath /** 172889a36810SAnil Ravindranath * pmcraid_get_error_info - return error string for an ioasc 172989a36810SAnil Ravindranath * @ioasc: ioasc code 173089a36810SAnil Ravindranath * Return Value 173189a36810SAnil Ravindranath * none 173289a36810SAnil Ravindranath */ 173389a36810SAnil Ravindranath static struct pmcraid_ioasc_error *pmcraid_get_error_info(u32 ioasc) 173489a36810SAnil Ravindranath { 173589a36810SAnil Ravindranath int i; 173689a36810SAnil Ravindranath for (i = 0; i < ARRAY_SIZE(pmcraid_ioasc_error_table); i++) { 173789a36810SAnil Ravindranath if (pmcraid_ioasc_error_table[i].ioasc_code == ioasc) 173889a36810SAnil Ravindranath return &pmcraid_ioasc_error_table[i]; 173989a36810SAnil Ravindranath } 174089a36810SAnil Ravindranath return NULL; 174189a36810SAnil Ravindranath } 174289a36810SAnil Ravindranath 174389a36810SAnil Ravindranath /** 174489a36810SAnil Ravindranath * pmcraid_ioasc_logger - log IOASC information based user-settings 174589a36810SAnil Ravindranath * @ioasc: ioasc code 174689a36810SAnil Ravindranath * @cmd: pointer to command that resulted in 'ioasc' 174789a36810SAnil Ravindranath */ 174889a36810SAnil Ravindranath void pmcraid_ioasc_logger(u32 ioasc, struct pmcraid_cmd *cmd) 174989a36810SAnil Ravindranath { 175089a36810SAnil Ravindranath struct pmcraid_ioasc_error *error_info = pmcraid_get_error_info(ioasc); 175189a36810SAnil Ravindranath 175289a36810SAnil Ravindranath if (error_info == NULL || 175389a36810SAnil Ravindranath cmd->drv_inst->current_log_level < error_info->log_level) 175489a36810SAnil Ravindranath return; 175589a36810SAnil Ravindranath 175689a36810SAnil Ravindranath /* log the error string */ 1757c20c4267SAnil Ravindranath pmcraid_err("cmd [%x] for resource %x failed with %x(%s)\n", 175889a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 175989a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.resource_handle, 176089a36810SAnil Ravindranath le32_to_cpu(ioasc), error_info->error_string); 176189a36810SAnil Ravindranath } 176289a36810SAnil Ravindranath 176389a36810SAnil Ravindranath /** 176489a36810SAnil Ravindranath * pmcraid_handle_error_log - Handle a config change (error log) from the IOA 176589a36810SAnil Ravindranath * 176689a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 176789a36810SAnil Ravindranath * 176889a36810SAnil Ravindranath * Return value: 176989a36810SAnil Ravindranath * none 177089a36810SAnil Ravindranath */ 177189a36810SAnil Ravindranath static void pmcraid_handle_error_log(struct pmcraid_instance *pinstance) 177289a36810SAnil Ravindranath { 177389a36810SAnil Ravindranath struct pmcraid_hcam_ldn *hcam_ldn; 177489a36810SAnil Ravindranath u32 ioasc; 177589a36810SAnil Ravindranath 177689a36810SAnil Ravindranath hcam_ldn = (struct pmcraid_hcam_ldn *)pinstance->ldn.hcam; 177789a36810SAnil Ravindranath 177889a36810SAnil Ravindranath pmcraid_info 177989a36810SAnil Ravindranath ("LDN(%x): %x type: %x lost: %x flags: %x overlay id: %x\n", 178089a36810SAnil Ravindranath pinstance->ldn.hcam->ilid, 178189a36810SAnil Ravindranath pinstance->ldn.hcam->op_code, 178289a36810SAnil Ravindranath pinstance->ldn.hcam->notification_type, 178389a36810SAnil Ravindranath pinstance->ldn.hcam->notification_lost, 178489a36810SAnil Ravindranath pinstance->ldn.hcam->flags, 178589a36810SAnil Ravindranath pinstance->ldn.hcam->overlay_id); 178689a36810SAnil Ravindranath 178789a36810SAnil Ravindranath /* log only the errors, no need to log informational log entries */ 178889a36810SAnil Ravindranath if (pinstance->ldn.hcam->notification_type != 178989a36810SAnil Ravindranath NOTIFICATION_TYPE_ERROR_LOG) 179089a36810SAnil Ravindranath return; 179189a36810SAnil Ravindranath 179289a36810SAnil Ravindranath if (pinstance->ldn.hcam->notification_lost == 179389a36810SAnil Ravindranath HOSTRCB_NOTIFICATIONS_LOST) 179434876402SAnil Ravindranath dev_info(&pinstance->pdev->dev, "Error notifications lost\n"); 179589a36810SAnil Ravindranath 179689a36810SAnil Ravindranath ioasc = le32_to_cpu(hcam_ldn->error_log.fd_ioasc); 179789a36810SAnil Ravindranath 179889a36810SAnil Ravindranath if (ioasc == PMCRAID_IOASC_UA_BUS_WAS_RESET || 179989a36810SAnil Ravindranath ioasc == PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER) { 180034876402SAnil Ravindranath dev_info(&pinstance->pdev->dev, 180189a36810SAnil Ravindranath "UnitAttention due to IOA Bus Reset\n"); 180289a36810SAnil Ravindranath scsi_report_bus_reset( 180389a36810SAnil Ravindranath pinstance->host, 180489a36810SAnil Ravindranath RES_BUS(hcam_ldn->error_log.fd_ra)); 180589a36810SAnil Ravindranath } 180689a36810SAnil Ravindranath 180789a36810SAnil Ravindranath return; 180889a36810SAnil Ravindranath } 180989a36810SAnil Ravindranath 181089a36810SAnil Ravindranath /** 181189a36810SAnil Ravindranath * pmcraid_process_ccn - Op done function for a CCN. 181289a36810SAnil Ravindranath * @cmd: pointer to command struct 181389a36810SAnil Ravindranath * 181489a36810SAnil Ravindranath * This function is the op done function for a configuration 181589a36810SAnil Ravindranath * change notification 181689a36810SAnil Ravindranath * 181789a36810SAnil Ravindranath * Return value: 181889a36810SAnil Ravindranath * none 181989a36810SAnil Ravindranath */ 182089a36810SAnil Ravindranath static void pmcraid_process_ccn(struct pmcraid_cmd *cmd) 182189a36810SAnil Ravindranath { 182289a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 182389a36810SAnil Ravindranath u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); 182489a36810SAnil Ravindranath unsigned long lock_flags; 182589a36810SAnil Ravindranath 182689a36810SAnil Ravindranath pinstance->ccn.cmd = NULL; 182789a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 182889a36810SAnil Ravindranath 182989a36810SAnil Ravindranath /* If driver initiated IOA reset happened while this hcam was pending 183089a36810SAnil Ravindranath * with IOA, or IOA bringdown sequence is in progress, no need to 183189a36810SAnil Ravindranath * re-register the hcam 183289a36810SAnil Ravindranath */ 183389a36810SAnil Ravindranath if (ioasc == PMCRAID_IOASC_IOA_WAS_RESET || 183489a36810SAnil Ravindranath atomic_read(&pinstance->ccn.ignore) == 1) { 183589a36810SAnil Ravindranath return; 183689a36810SAnil Ravindranath } else if (ioasc) { 183734876402SAnil Ravindranath dev_info(&pinstance->pdev->dev, 183889a36810SAnil Ravindranath "Host RCB (CCN) failed with IOASC: 0x%08X\n", ioasc); 183989a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 184089a36810SAnil Ravindranath pmcraid_send_hcam(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE); 184189a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 184289a36810SAnil Ravindranath } else { 184389a36810SAnil Ravindranath pmcraid_handle_config_change(pinstance); 184489a36810SAnil Ravindranath } 184589a36810SAnil Ravindranath } 184689a36810SAnil Ravindranath 184789a36810SAnil Ravindranath /** 184889a36810SAnil Ravindranath * pmcraid_process_ldn - op done function for an LDN 184989a36810SAnil Ravindranath * @cmd: pointer to command block 185089a36810SAnil Ravindranath * 185189a36810SAnil Ravindranath * Return value 185289a36810SAnil Ravindranath * none 185389a36810SAnil Ravindranath */ 185489a36810SAnil Ravindranath static void pmcraid_initiate_reset(struct pmcraid_instance *); 1855592488a3SAnil Ravindranath static void pmcraid_set_timestamp(struct pmcraid_cmd *cmd); 185689a36810SAnil Ravindranath 185789a36810SAnil Ravindranath static void pmcraid_process_ldn(struct pmcraid_cmd *cmd) 185889a36810SAnil Ravindranath { 185989a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 186089a36810SAnil Ravindranath struct pmcraid_hcam_ldn *ldn_hcam = 186189a36810SAnil Ravindranath (struct pmcraid_hcam_ldn *)pinstance->ldn.hcam; 186289a36810SAnil Ravindranath u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); 186389a36810SAnil Ravindranath u32 fd_ioasc = le32_to_cpu(ldn_hcam->error_log.fd_ioasc); 186489a36810SAnil Ravindranath unsigned long lock_flags; 186589a36810SAnil Ravindranath 186689a36810SAnil Ravindranath /* return the command block back to freepool */ 186789a36810SAnil Ravindranath pinstance->ldn.cmd = NULL; 186889a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 186989a36810SAnil Ravindranath 187089a36810SAnil Ravindranath /* If driver initiated IOA reset happened while this hcam was pending 187189a36810SAnil Ravindranath * with IOA, no need to re-register the hcam as reset engine will do it 187289a36810SAnil Ravindranath * once reset sequence is complete 187389a36810SAnil Ravindranath */ 187489a36810SAnil Ravindranath if (ioasc == PMCRAID_IOASC_IOA_WAS_RESET || 187589a36810SAnil Ravindranath atomic_read(&pinstance->ccn.ignore) == 1) { 187689a36810SAnil Ravindranath return; 187789a36810SAnil Ravindranath } else if (!ioasc) { 187889a36810SAnil Ravindranath pmcraid_handle_error_log(pinstance); 187989a36810SAnil Ravindranath if (fd_ioasc == PMCRAID_IOASC_NR_IOA_RESET_REQUIRED) { 188089a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, 188189a36810SAnil Ravindranath lock_flags); 188289a36810SAnil Ravindranath pmcraid_initiate_reset(pinstance); 188389a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 188489a36810SAnil Ravindranath lock_flags); 188589a36810SAnil Ravindranath return; 188689a36810SAnil Ravindranath } 1887592488a3SAnil Ravindranath if (fd_ioasc == PMCRAID_IOASC_TIME_STAMP_OUT_OF_SYNC) { 1888592488a3SAnil Ravindranath pinstance->timestamp_error = 1; 1889592488a3SAnil Ravindranath pmcraid_set_timestamp(cmd); 1890592488a3SAnil Ravindranath } 189189a36810SAnil Ravindranath } else { 189234876402SAnil Ravindranath dev_info(&pinstance->pdev->dev, 189389a36810SAnil Ravindranath "Host RCB(LDN) failed with IOASC: 0x%08X\n", ioasc); 189489a36810SAnil Ravindranath } 189589a36810SAnil Ravindranath /* send netlink message for HCAM notification if enabled */ 189689a36810SAnil Ravindranath if (!pmcraid_disable_aen) 1897c20c4267SAnil Ravindranath pmcraid_notify_ldn(pinstance); 189889a36810SAnil Ravindranath 189989a36810SAnil Ravindranath cmd = pmcraid_init_hcam(pinstance, PMCRAID_HCAM_CODE_LOG_DATA); 190089a36810SAnil Ravindranath if (cmd) 190189a36810SAnil Ravindranath pmcraid_send_hcam_cmd(cmd); 190289a36810SAnil Ravindranath } 190389a36810SAnil Ravindranath 190489a36810SAnil Ravindranath /** 190589a36810SAnil Ravindranath * pmcraid_register_hcams - register HCAMs for CCN and LDN 190689a36810SAnil Ravindranath * 190789a36810SAnil Ravindranath * @pinstance: pointer per adapter instance structure 190889a36810SAnil Ravindranath * 190989a36810SAnil Ravindranath * Return Value 191089a36810SAnil Ravindranath * none 191189a36810SAnil Ravindranath */ 191289a36810SAnil Ravindranath static void pmcraid_register_hcams(struct pmcraid_instance *pinstance) 191389a36810SAnil Ravindranath { 191489a36810SAnil Ravindranath pmcraid_send_hcam(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE); 191589a36810SAnil Ravindranath pmcraid_send_hcam(pinstance, PMCRAID_HCAM_CODE_LOG_DATA); 191689a36810SAnil Ravindranath } 191789a36810SAnil Ravindranath 191889a36810SAnil Ravindranath /** 191989a36810SAnil Ravindranath * pmcraid_unregister_hcams - cancel HCAMs registered already 192089a36810SAnil Ravindranath * @cmd: pointer to command used as part of reset sequence 192189a36810SAnil Ravindranath */ 192289a36810SAnil Ravindranath static void pmcraid_unregister_hcams(struct pmcraid_cmd *cmd) 192389a36810SAnil Ravindranath { 192489a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 192589a36810SAnil Ravindranath 192689a36810SAnil Ravindranath /* During IOA bringdown, HCAM gets fired and tasklet proceeds with 192789a36810SAnil Ravindranath * handling hcam response though it is not necessary. In order to 192889a36810SAnil Ravindranath * prevent this, set 'ignore', so that bring-down sequence doesn't 192989a36810SAnil Ravindranath * re-send any more hcams 193089a36810SAnil Ravindranath */ 193189a36810SAnil Ravindranath atomic_set(&pinstance->ccn.ignore, 1); 193289a36810SAnil Ravindranath atomic_set(&pinstance->ldn.ignore, 1); 193389a36810SAnil Ravindranath 193489a36810SAnil Ravindranath /* If adapter reset was forced as part of runtime reset sequence, 1935c20c4267SAnil Ravindranath * start the reset sequence. Reset will be triggered even in case 1936c20c4267SAnil Ravindranath * IOA unit_check. 193789a36810SAnil Ravindranath */ 1938c20c4267SAnil Ravindranath if ((pinstance->force_ioa_reset && !pinstance->ioa_bringdown) || 1939c20c4267SAnil Ravindranath pinstance->ioa_unit_check) { 194089a36810SAnil Ravindranath pinstance->force_ioa_reset = 0; 1941c20c4267SAnil Ravindranath pinstance->ioa_unit_check = 0; 194289a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; 194389a36810SAnil Ravindranath pmcraid_reset_alert(cmd); 194489a36810SAnil Ravindranath return; 194589a36810SAnil Ravindranath } 194689a36810SAnil Ravindranath 194789a36810SAnil Ravindranath /* Driver tries to cancel HCAMs by sending ABORT TASK for each HCAM 194889a36810SAnil Ravindranath * one after the other. So CCN cancellation will be triggered by 194989a36810SAnil Ravindranath * pmcraid_cancel_ldn itself. 195089a36810SAnil Ravindranath */ 195189a36810SAnil Ravindranath pmcraid_cancel_ldn(cmd); 195289a36810SAnil Ravindranath } 195389a36810SAnil Ravindranath 195489a36810SAnil Ravindranath /** 195589a36810SAnil Ravindranath * pmcraid_reset_enable_ioa - re-enable IOA after a hard reset 195689a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 195789a36810SAnil Ravindranath * Return Value 195889a36810SAnil Ravindranath * 1 if TRANSITION_TO_OPERATIONAL is active, otherwise 0 195989a36810SAnil Ravindranath */ 196089a36810SAnil Ravindranath static void pmcraid_reinit_buffers(struct pmcraid_instance *); 196189a36810SAnil Ravindranath 196289a36810SAnil Ravindranath static int pmcraid_reset_enable_ioa(struct pmcraid_instance *pinstance) 196389a36810SAnil Ravindranath { 196489a36810SAnil Ravindranath u32 intrs; 196589a36810SAnil Ravindranath 196689a36810SAnil Ravindranath pmcraid_reinit_buffers(pinstance); 196789a36810SAnil Ravindranath intrs = pmcraid_read_interrupts(pinstance); 196889a36810SAnil Ravindranath 196989a36810SAnil Ravindranath pmcraid_enable_interrupts(pinstance, PMCRAID_PCI_INTERRUPTS); 197089a36810SAnil Ravindranath 197189a36810SAnil Ravindranath if (intrs & INTRS_TRANSITION_TO_OPERATIONAL) { 1972c20c4267SAnil Ravindranath if (!pinstance->interrupt_mode) { 197389a36810SAnil Ravindranath iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, 1974c20c4267SAnil Ravindranath pinstance->int_regs. 1975c20c4267SAnil Ravindranath ioa_host_interrupt_mask_reg); 197689a36810SAnil Ravindranath iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, 197789a36810SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_clr_reg); 1978c20c4267SAnil Ravindranath } 197989a36810SAnil Ravindranath return 1; 198089a36810SAnil Ravindranath } else { 198189a36810SAnil Ravindranath return 0; 198289a36810SAnil Ravindranath } 198389a36810SAnil Ravindranath } 198489a36810SAnil Ravindranath 198589a36810SAnil Ravindranath /** 198689a36810SAnil Ravindranath * pmcraid_soft_reset - performs a soft reset and makes IOA become ready 198789a36810SAnil Ravindranath * @cmd : pointer to reset command block 198889a36810SAnil Ravindranath * 198989a36810SAnil Ravindranath * Return Value 199089a36810SAnil Ravindranath * none 199189a36810SAnil Ravindranath */ 199289a36810SAnil Ravindranath static void pmcraid_soft_reset(struct pmcraid_cmd *cmd) 199389a36810SAnil Ravindranath { 199489a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 199589a36810SAnil Ravindranath u32 int_reg; 199689a36810SAnil Ravindranath u32 doorbell; 199789a36810SAnil Ravindranath 199889a36810SAnil Ravindranath /* There will be an interrupt when Transition to Operational bit is 199989a36810SAnil Ravindranath * set so tasklet would execute next reset task. The timeout handler 200089a36810SAnil Ravindranath * would re-initiate a reset 200189a36810SAnil Ravindranath */ 200289a36810SAnil Ravindranath cmd->cmd_done = pmcraid_ioa_reset; 200389a36810SAnil Ravindranath cmd->timer.data = (unsigned long)cmd; 200489a36810SAnil Ravindranath cmd->timer.expires = jiffies + 200589a36810SAnil Ravindranath msecs_to_jiffies(PMCRAID_TRANSOP_TIMEOUT); 200689a36810SAnil Ravindranath cmd->timer.function = (void (*)(unsigned long))pmcraid_timeout_handler; 200789a36810SAnil Ravindranath 200889a36810SAnil Ravindranath if (!timer_pending(&cmd->timer)) 200989a36810SAnil Ravindranath add_timer(&cmd->timer); 201089a36810SAnil Ravindranath 201189a36810SAnil Ravindranath /* Enable destructive diagnostics on IOA if it is not yet in 201289a36810SAnil Ravindranath * operational state 201389a36810SAnil Ravindranath */ 201489a36810SAnil Ravindranath doorbell = DOORBELL_RUNTIME_RESET | 201589a36810SAnil Ravindranath DOORBELL_ENABLE_DESTRUCTIVE_DIAGS; 201689a36810SAnil Ravindranath 2017c20c4267SAnil Ravindranath /* Since we do RESET_ALERT and Start BIST we have to again write 2018c20c4267SAnil Ravindranath * MSIX Doorbell to indicate the interrupt mode 2019c20c4267SAnil Ravindranath */ 2020c20c4267SAnil Ravindranath if (pinstance->interrupt_mode) { 2021c20c4267SAnil Ravindranath iowrite32(DOORBELL_INTR_MODE_MSIX, 2022c20c4267SAnil Ravindranath pinstance->int_regs.host_ioa_interrupt_reg); 2023c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.host_ioa_interrupt_reg); 2024c20c4267SAnil Ravindranath } 2025c20c4267SAnil Ravindranath 202689a36810SAnil Ravindranath iowrite32(doorbell, pinstance->int_regs.host_ioa_interrupt_reg); 2027c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.host_ioa_interrupt_reg), 202889a36810SAnil Ravindranath int_reg = ioread32(pinstance->int_regs.ioa_host_interrupt_reg); 2029c20c4267SAnil Ravindranath 203089a36810SAnil Ravindranath pmcraid_info("Waiting for IOA to become operational %x:%x\n", 203189a36810SAnil Ravindranath ioread32(pinstance->int_regs.host_ioa_interrupt_reg), 203289a36810SAnil Ravindranath int_reg); 203389a36810SAnil Ravindranath } 203489a36810SAnil Ravindranath 203589a36810SAnil Ravindranath /** 203689a36810SAnil Ravindranath * pmcraid_get_dump - retrieves IOA dump in case of Unit Check interrupt 203789a36810SAnil Ravindranath * 203889a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 203989a36810SAnil Ravindranath * 204089a36810SAnil Ravindranath * Return Value 204189a36810SAnil Ravindranath * none 204289a36810SAnil Ravindranath */ 204389a36810SAnil Ravindranath static void pmcraid_get_dump(struct pmcraid_instance *pinstance) 204489a36810SAnil Ravindranath { 204589a36810SAnil Ravindranath pmcraid_info("%s is not yet implemented\n", __func__); 204689a36810SAnil Ravindranath } 204789a36810SAnil Ravindranath 204889a36810SAnil Ravindranath /** 204989a36810SAnil Ravindranath * pmcraid_fail_outstanding_cmds - Fails all outstanding ops. 205089a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 205189a36810SAnil Ravindranath * 205289a36810SAnil Ravindranath * This function fails all outstanding ops. If they are submitted to IOA 205389a36810SAnil Ravindranath * already, it sends cancel all messages if IOA is still accepting IOARCBs, 205489a36810SAnil Ravindranath * otherwise just completes the commands and returns the cmd blocks to free 205589a36810SAnil Ravindranath * pool. 205689a36810SAnil Ravindranath * 205789a36810SAnil Ravindranath * Return value: 205889a36810SAnil Ravindranath * none 205989a36810SAnil Ravindranath */ 206089a36810SAnil Ravindranath static void pmcraid_fail_outstanding_cmds(struct pmcraid_instance *pinstance) 206189a36810SAnil Ravindranath { 206289a36810SAnil Ravindranath struct pmcraid_cmd *cmd, *temp; 206389a36810SAnil Ravindranath unsigned long lock_flags; 206489a36810SAnil Ravindranath 206589a36810SAnil Ravindranath /* pending command list is protected by pending_pool_lock. Its 206689a36810SAnil Ravindranath * traversal must be done as within this lock 206789a36810SAnil Ravindranath */ 206889a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->pending_pool_lock, lock_flags); 206989a36810SAnil Ravindranath list_for_each_entry_safe(cmd, temp, &pinstance->pending_cmd_pool, 207089a36810SAnil Ravindranath free_list) { 207189a36810SAnil Ravindranath list_del(&cmd->free_list); 207289a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->pending_pool_lock, 207389a36810SAnil Ravindranath lock_flags); 207489a36810SAnil Ravindranath cmd->ioa_cb->ioasa.ioasc = 207589a36810SAnil Ravindranath cpu_to_le32(PMCRAID_IOASC_IOA_WAS_RESET); 207689a36810SAnil Ravindranath cmd->ioa_cb->ioasa.ilid = 207789a36810SAnil Ravindranath cpu_to_be32(PMCRAID_DRIVER_ILID); 207889a36810SAnil Ravindranath 207989a36810SAnil Ravindranath /* In case the command timer is still running */ 208089a36810SAnil Ravindranath del_timer(&cmd->timer); 208189a36810SAnil Ravindranath 208289a36810SAnil Ravindranath /* If this is an IO command, complete it by invoking scsi_done 208389a36810SAnil Ravindranath * function. If this is one of the internal commands other 208489a36810SAnil Ravindranath * than pmcraid_ioa_reset and HCAM commands invoke cmd_done to 208589a36810SAnil Ravindranath * complete it 208689a36810SAnil Ravindranath */ 208789a36810SAnil Ravindranath if (cmd->scsi_cmd) { 208889a36810SAnil Ravindranath 208989a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; 209089a36810SAnil Ravindranath __le32 resp = cmd->ioa_cb->ioarcb.response_handle; 209189a36810SAnil Ravindranath 209289a36810SAnil Ravindranath scsi_cmd->result |= DID_ERROR << 16; 209389a36810SAnil Ravindranath 209489a36810SAnil Ravindranath scsi_dma_unmap(scsi_cmd); 209589a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 209689a36810SAnil Ravindranath 209789a36810SAnil Ravindranath pmcraid_info("failing(%d) CDB[0] = %x result: %x\n", 209889a36810SAnil Ravindranath le32_to_cpu(resp) >> 2, 209989a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 210089a36810SAnil Ravindranath scsi_cmd->result); 210189a36810SAnil Ravindranath scsi_cmd->scsi_done(scsi_cmd); 210289a36810SAnil Ravindranath } else if (cmd->cmd_done == pmcraid_internal_done || 210389a36810SAnil Ravindranath cmd->cmd_done == pmcraid_erp_done) { 210489a36810SAnil Ravindranath cmd->cmd_done(cmd); 2105c20c4267SAnil Ravindranath } else if (cmd->cmd_done != pmcraid_ioa_reset && 2106c20c4267SAnil Ravindranath cmd->cmd_done != pmcraid_ioa_shutdown_done) { 210789a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 210889a36810SAnil Ravindranath } 210989a36810SAnil Ravindranath 211089a36810SAnil Ravindranath atomic_dec(&pinstance->outstanding_cmds); 211189a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->pending_pool_lock, lock_flags); 211289a36810SAnil Ravindranath } 211389a36810SAnil Ravindranath 211489a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->pending_pool_lock, lock_flags); 211589a36810SAnil Ravindranath } 211689a36810SAnil Ravindranath 211789a36810SAnil Ravindranath /** 211889a36810SAnil Ravindranath * pmcraid_ioa_reset - Implementation of IOA reset logic 211989a36810SAnil Ravindranath * 212089a36810SAnil Ravindranath * @cmd: pointer to the cmd block to be used for entire reset process 212189a36810SAnil Ravindranath * 212289a36810SAnil Ravindranath * This function executes most of the steps required for IOA reset. This gets 212389a36810SAnil Ravindranath * called by user threads (modprobe/insmod/rmmod) timer, tasklet and midlayer's 212425985edcSLucas De Marchi * 'eh_' thread. Access to variables used for controlling the reset sequence is 212589a36810SAnil Ravindranath * synchronized using host lock. Various functions called during reset process 212689a36810SAnil Ravindranath * would make use of a single command block, pointer to which is also stored in 212789a36810SAnil Ravindranath * adapter instance structure. 212889a36810SAnil Ravindranath * 212989a36810SAnil Ravindranath * Return Value 213089a36810SAnil Ravindranath * None 213189a36810SAnil Ravindranath */ 213289a36810SAnil Ravindranath static void pmcraid_ioa_reset(struct pmcraid_cmd *cmd) 213389a36810SAnil Ravindranath { 213489a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 213589a36810SAnil Ravindranath u8 reset_complete = 0; 213689a36810SAnil Ravindranath 213789a36810SAnil Ravindranath pinstance->ioa_reset_in_progress = 1; 213889a36810SAnil Ravindranath 213989a36810SAnil Ravindranath if (pinstance->reset_cmd != cmd) { 214089a36810SAnil Ravindranath pmcraid_err("reset is called with different command block\n"); 214189a36810SAnil Ravindranath pinstance->reset_cmd = cmd; 214289a36810SAnil Ravindranath } 214389a36810SAnil Ravindranath 214489a36810SAnil Ravindranath pmcraid_info("reset_engine: state = %d, command = %p\n", 214589a36810SAnil Ravindranath pinstance->ioa_state, cmd); 214689a36810SAnil Ravindranath 214789a36810SAnil Ravindranath switch (pinstance->ioa_state) { 214889a36810SAnil Ravindranath 214989a36810SAnil Ravindranath case IOA_STATE_DEAD: 215089a36810SAnil Ravindranath /* If IOA is offline, whatever may be the reset reason, just 215189a36810SAnil Ravindranath * return. callers might be waiting on the reset wait_q, wake 215289a36810SAnil Ravindranath * up them 215389a36810SAnil Ravindranath */ 215489a36810SAnil Ravindranath pmcraid_err("IOA is offline no reset is possible\n"); 215589a36810SAnil Ravindranath reset_complete = 1; 215689a36810SAnil Ravindranath break; 215789a36810SAnil Ravindranath 215889a36810SAnil Ravindranath case IOA_STATE_IN_BRINGDOWN: 215989a36810SAnil Ravindranath /* we enter here, once ioa shutdown command is processed by IOA 216089a36810SAnil Ravindranath * Alert IOA for a possible reset. If reset alert fails, IOA 216189a36810SAnil Ravindranath * goes through hard-reset 216289a36810SAnil Ravindranath */ 216389a36810SAnil Ravindranath pmcraid_disable_interrupts(pinstance, ~0); 216489a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; 216589a36810SAnil Ravindranath pmcraid_reset_alert(cmd); 216689a36810SAnil Ravindranath break; 216789a36810SAnil Ravindranath 216889a36810SAnil Ravindranath case IOA_STATE_UNKNOWN: 216989a36810SAnil Ravindranath /* We may be called during probe or resume. Some pre-processing 217089a36810SAnil Ravindranath * is required for prior to reset 217189a36810SAnil Ravindranath */ 217289a36810SAnil Ravindranath scsi_block_requests(pinstance->host); 217389a36810SAnil Ravindranath 217489a36810SAnil Ravindranath /* If asked to reset while IOA was processing responses or 217589a36810SAnil Ravindranath * there are any error responses then IOA may require 217689a36810SAnil Ravindranath * hard-reset. 217789a36810SAnil Ravindranath */ 217889a36810SAnil Ravindranath if (pinstance->ioa_hard_reset == 0) { 217989a36810SAnil Ravindranath if (ioread32(pinstance->ioa_status) & 218089a36810SAnil Ravindranath INTRS_TRANSITION_TO_OPERATIONAL) { 218189a36810SAnil Ravindranath pmcraid_info("sticky bit set, bring-up\n"); 218289a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_BRINGUP; 218389a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 218489a36810SAnil Ravindranath pmcraid_identify_hrrq(cmd); 218589a36810SAnil Ravindranath } else { 218689a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_SOFT_RESET; 218789a36810SAnil Ravindranath pmcraid_soft_reset(cmd); 218889a36810SAnil Ravindranath } 218989a36810SAnil Ravindranath } else { 219089a36810SAnil Ravindranath /* Alert IOA of a possible reset and wait for critical 219189a36810SAnil Ravindranath * operation in progress bit to reset 219289a36810SAnil Ravindranath */ 219389a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; 219489a36810SAnil Ravindranath pmcraid_reset_alert(cmd); 219589a36810SAnil Ravindranath } 219689a36810SAnil Ravindranath break; 219789a36810SAnil Ravindranath 219889a36810SAnil Ravindranath case IOA_STATE_IN_RESET_ALERT: 219989a36810SAnil Ravindranath /* If critical operation in progress bit is reset or wait gets 220089a36810SAnil Ravindranath * timed out, reset proceeds with starting BIST on the IOA. 220189a36810SAnil Ravindranath * pmcraid_ioa_hard_reset keeps a count of reset attempts. If 220289a36810SAnil Ravindranath * they are 3 or more, reset engine marks IOA dead and returns 220389a36810SAnil Ravindranath */ 220489a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_HARD_RESET; 220589a36810SAnil Ravindranath pmcraid_start_bist(cmd); 220689a36810SAnil Ravindranath break; 220789a36810SAnil Ravindranath 220889a36810SAnil Ravindranath case IOA_STATE_IN_HARD_RESET: 220989a36810SAnil Ravindranath pinstance->ioa_reset_attempts++; 221089a36810SAnil Ravindranath 221189a36810SAnil Ravindranath /* retry reset if we haven't reached maximum allowed limit */ 221289a36810SAnil Ravindranath if (pinstance->ioa_reset_attempts > PMCRAID_RESET_ATTEMPTS) { 221389a36810SAnil Ravindranath pinstance->ioa_reset_attempts = 0; 221489a36810SAnil Ravindranath pmcraid_err("IOA didn't respond marking it as dead\n"); 221589a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_DEAD; 2216c20c4267SAnil Ravindranath 2217c20c4267SAnil Ravindranath if (pinstance->ioa_bringdown) 2218c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, 2219c20c4267SAnil Ravindranath PMC_DEVICE_EVENT_SHUTDOWN_FAILED); 2220c20c4267SAnil Ravindranath else 2221c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, 2222c20c4267SAnil Ravindranath PMC_DEVICE_EVENT_RESET_FAILED); 222389a36810SAnil Ravindranath reset_complete = 1; 222489a36810SAnil Ravindranath break; 222589a36810SAnil Ravindranath } 222689a36810SAnil Ravindranath 222789a36810SAnil Ravindranath /* Once either bist or pci reset is done, restore PCI config 222889a36810SAnil Ravindranath * space. If this fails, proceed with hard reset again 222989a36810SAnil Ravindranath */ 22301d3c16a8SJon Mason pci_restore_state(pinstance->pdev); 223189a36810SAnil Ravindranath 223289a36810SAnil Ravindranath /* fail all pending commands */ 223389a36810SAnil Ravindranath pmcraid_fail_outstanding_cmds(pinstance); 223489a36810SAnil Ravindranath 223589a36810SAnil Ravindranath /* check if unit check is active, if so extract dump */ 223689a36810SAnil Ravindranath if (pinstance->ioa_unit_check) { 223789a36810SAnil Ravindranath pmcraid_info("unit check is active\n"); 223889a36810SAnil Ravindranath pinstance->ioa_unit_check = 0; 223989a36810SAnil Ravindranath pmcraid_get_dump(pinstance); 224089a36810SAnil Ravindranath pinstance->ioa_reset_attempts--; 224189a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; 224289a36810SAnil Ravindranath pmcraid_reset_alert(cmd); 224389a36810SAnil Ravindranath break; 224489a36810SAnil Ravindranath } 224589a36810SAnil Ravindranath 224689a36810SAnil Ravindranath /* if the reset reason is to bring-down the ioa, we might be 224789a36810SAnil Ravindranath * done with the reset restore pci_config_space and complete 224889a36810SAnil Ravindranath * the reset 224989a36810SAnil Ravindranath */ 225089a36810SAnil Ravindranath if (pinstance->ioa_bringdown) { 225189a36810SAnil Ravindranath pmcraid_info("bringing down the adapter\n"); 225289a36810SAnil Ravindranath pinstance->ioa_shutdown_type = SHUTDOWN_NONE; 225389a36810SAnil Ravindranath pinstance->ioa_bringdown = 0; 225489a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_UNKNOWN; 2255c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, 2256c20c4267SAnil Ravindranath PMC_DEVICE_EVENT_SHUTDOWN_SUCCESS); 225789a36810SAnil Ravindranath reset_complete = 1; 225889a36810SAnil Ravindranath } else { 225989a36810SAnil Ravindranath /* bring-up IOA, so proceed with soft reset 226089a36810SAnil Ravindranath * Reinitialize hrrq_buffers and their indices also 226189a36810SAnil Ravindranath * enable interrupts after a pci_restore_state 226289a36810SAnil Ravindranath */ 226389a36810SAnil Ravindranath if (pmcraid_reset_enable_ioa(pinstance)) { 226489a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_BRINGUP; 226589a36810SAnil Ravindranath pmcraid_info("bringing up the adapter\n"); 226689a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 226789a36810SAnil Ravindranath pmcraid_identify_hrrq(cmd); 226889a36810SAnil Ravindranath } else { 226989a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_SOFT_RESET; 227089a36810SAnil Ravindranath pmcraid_soft_reset(cmd); 227189a36810SAnil Ravindranath } 227289a36810SAnil Ravindranath } 227389a36810SAnil Ravindranath break; 227489a36810SAnil Ravindranath 227589a36810SAnil Ravindranath case IOA_STATE_IN_SOFT_RESET: 227689a36810SAnil Ravindranath /* TRANSITION TO OPERATIONAL is on so start initialization 227789a36810SAnil Ravindranath * sequence 227889a36810SAnil Ravindranath */ 227989a36810SAnil Ravindranath pmcraid_info("In softreset proceeding with bring-up\n"); 228089a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_BRINGUP; 228189a36810SAnil Ravindranath 228289a36810SAnil Ravindranath /* Initialization commands start with HRRQ identification. From 228389a36810SAnil Ravindranath * now on tasklet completes most of the commands as IOA is up 228489a36810SAnil Ravindranath * and intrs are enabled 228589a36810SAnil Ravindranath */ 228689a36810SAnil Ravindranath pmcraid_identify_hrrq(cmd); 228789a36810SAnil Ravindranath break; 228889a36810SAnil Ravindranath 228989a36810SAnil Ravindranath case IOA_STATE_IN_BRINGUP: 229089a36810SAnil Ravindranath /* we are done with bringing up of IOA, change the ioa_state to 229189a36810SAnil Ravindranath * operational and wake up any waiters 229289a36810SAnil Ravindranath */ 229389a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_OPERATIONAL; 229489a36810SAnil Ravindranath reset_complete = 1; 229589a36810SAnil Ravindranath break; 229689a36810SAnil Ravindranath 229789a36810SAnil Ravindranath case IOA_STATE_OPERATIONAL: 229889a36810SAnil Ravindranath default: 229989a36810SAnil Ravindranath /* When IOA is operational and a reset is requested, check for 230089a36810SAnil Ravindranath * the reset reason. If reset is to bring down IOA, unregister 230189a36810SAnil Ravindranath * HCAMs and initiate shutdown; if adapter reset is forced then 230289a36810SAnil Ravindranath * restart reset sequence again 230389a36810SAnil Ravindranath */ 230489a36810SAnil Ravindranath if (pinstance->ioa_shutdown_type == SHUTDOWN_NONE && 230589a36810SAnil Ravindranath pinstance->force_ioa_reset == 0) { 2306c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, 2307c20c4267SAnil Ravindranath PMC_DEVICE_EVENT_RESET_SUCCESS); 230889a36810SAnil Ravindranath reset_complete = 1; 230989a36810SAnil Ravindranath } else { 231089a36810SAnil Ravindranath if (pinstance->ioa_shutdown_type != SHUTDOWN_NONE) 231189a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_BRINGDOWN; 231289a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 231389a36810SAnil Ravindranath pmcraid_unregister_hcams(cmd); 231489a36810SAnil Ravindranath } 231589a36810SAnil Ravindranath break; 231689a36810SAnil Ravindranath } 231789a36810SAnil Ravindranath 231889a36810SAnil Ravindranath /* reset will be completed if ioa_state is either DEAD or UNKNOWN or 231989a36810SAnil Ravindranath * OPERATIONAL. Reset all control variables used during reset, wake up 232089a36810SAnil Ravindranath * any waiting threads and let the SCSI mid-layer send commands. Note 232189a36810SAnil Ravindranath * that host_lock must be held before invoking scsi_report_bus_reset. 232289a36810SAnil Ravindranath */ 232389a36810SAnil Ravindranath if (reset_complete) { 232489a36810SAnil Ravindranath pinstance->ioa_reset_in_progress = 0; 232589a36810SAnil Ravindranath pinstance->ioa_reset_attempts = 0; 232689a36810SAnil Ravindranath pinstance->reset_cmd = NULL; 232789a36810SAnil Ravindranath pinstance->ioa_shutdown_type = SHUTDOWN_NONE; 232889a36810SAnil Ravindranath pinstance->ioa_bringdown = 0; 232989a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 233089a36810SAnil Ravindranath 233189a36810SAnil Ravindranath /* If target state is to bring up the adapter, proceed with 233289a36810SAnil Ravindranath * hcam registration and resource exposure to mid-layer. 233389a36810SAnil Ravindranath */ 233489a36810SAnil Ravindranath if (pinstance->ioa_state == IOA_STATE_OPERATIONAL) 233589a36810SAnil Ravindranath pmcraid_register_hcams(pinstance); 233689a36810SAnil Ravindranath 233789a36810SAnil Ravindranath wake_up_all(&pinstance->reset_wait_q); 233889a36810SAnil Ravindranath } 233989a36810SAnil Ravindranath 234089a36810SAnil Ravindranath return; 234189a36810SAnil Ravindranath } 234289a36810SAnil Ravindranath 234389a36810SAnil Ravindranath /** 234489a36810SAnil Ravindranath * pmcraid_initiate_reset - initiates reset sequence. This is called from 234589a36810SAnil Ravindranath * ISR/tasklet during error interrupts including IOA unit check. If reset 234689a36810SAnil Ravindranath * is already in progress, it just returns, otherwise initiates IOA reset 234789a36810SAnil Ravindranath * to bring IOA up to operational state. 234889a36810SAnil Ravindranath * 234989a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 235089a36810SAnil Ravindranath * 235189a36810SAnil Ravindranath * Return value 235289a36810SAnil Ravindranath * none 235389a36810SAnil Ravindranath */ 235489a36810SAnil Ravindranath static void pmcraid_initiate_reset(struct pmcraid_instance *pinstance) 235589a36810SAnil Ravindranath { 235689a36810SAnil Ravindranath struct pmcraid_cmd *cmd; 235789a36810SAnil Ravindranath 235889a36810SAnil Ravindranath /* If the reset is already in progress, just return, otherwise start 235989a36810SAnil Ravindranath * reset sequence and return 236089a36810SAnil Ravindranath */ 236189a36810SAnil Ravindranath if (!pinstance->ioa_reset_in_progress) { 236289a36810SAnil Ravindranath scsi_block_requests(pinstance->host); 236389a36810SAnil Ravindranath cmd = pmcraid_get_free_cmd(pinstance); 236489a36810SAnil Ravindranath 236589a36810SAnil Ravindranath if (cmd == NULL) { 236689a36810SAnil Ravindranath pmcraid_err("no cmnd blocks for initiate_reset\n"); 236789a36810SAnil Ravindranath return; 236889a36810SAnil Ravindranath } 236989a36810SAnil Ravindranath 237089a36810SAnil Ravindranath pinstance->ioa_shutdown_type = SHUTDOWN_NONE; 237189a36810SAnil Ravindranath pinstance->reset_cmd = cmd; 237289a36810SAnil Ravindranath pinstance->force_ioa_reset = 1; 2373c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, 2374c20c4267SAnil Ravindranath PMC_DEVICE_EVENT_RESET_START); 237589a36810SAnil Ravindranath pmcraid_ioa_reset(cmd); 237689a36810SAnil Ravindranath } 237789a36810SAnil Ravindranath } 237889a36810SAnil Ravindranath 237989a36810SAnil Ravindranath /** 238089a36810SAnil Ravindranath * pmcraid_reset_reload - utility routine for doing IOA reset either to bringup 238189a36810SAnil Ravindranath * or bringdown IOA 238289a36810SAnil Ravindranath * @pinstance: pointer adapter instance structure 238389a36810SAnil Ravindranath * @shutdown_type: shutdown type to be used NONE, NORMAL or ABRREV 238489a36810SAnil Ravindranath * @target_state: expected target state after reset 238589a36810SAnil Ravindranath * 238689a36810SAnil Ravindranath * Note: This command initiates reset and waits for its completion. Hence this 238789a36810SAnil Ravindranath * should not be called from isr/timer/tasklet functions (timeout handlers, 238889a36810SAnil Ravindranath * error response handlers and interrupt handlers). 238989a36810SAnil Ravindranath * 239089a36810SAnil Ravindranath * Return Value 239189a36810SAnil Ravindranath * 1 in case ioa_state is not target_state, 0 otherwise. 239289a36810SAnil Ravindranath */ 239389a36810SAnil Ravindranath static int pmcraid_reset_reload( 239489a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 239589a36810SAnil Ravindranath u8 shutdown_type, 239689a36810SAnil Ravindranath u8 target_state 239789a36810SAnil Ravindranath ) 239889a36810SAnil Ravindranath { 239989a36810SAnil Ravindranath struct pmcraid_cmd *reset_cmd = NULL; 240089a36810SAnil Ravindranath unsigned long lock_flags; 240189a36810SAnil Ravindranath int reset = 1; 240289a36810SAnil Ravindranath 240389a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 240489a36810SAnil Ravindranath 240589a36810SAnil Ravindranath if (pinstance->ioa_reset_in_progress) { 240689a36810SAnil Ravindranath pmcraid_info("reset_reload: reset is already in progress\n"); 240789a36810SAnil Ravindranath 240889a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 240989a36810SAnil Ravindranath 241089a36810SAnil Ravindranath wait_event(pinstance->reset_wait_q, 241189a36810SAnil Ravindranath !pinstance->ioa_reset_in_progress); 241289a36810SAnil Ravindranath 241389a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 241489a36810SAnil Ravindranath 241589a36810SAnil Ravindranath if (pinstance->ioa_state == IOA_STATE_DEAD) { 241689a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 241789a36810SAnil Ravindranath lock_flags); 241889a36810SAnil Ravindranath pmcraid_info("reset_reload: IOA is dead\n"); 241989a36810SAnil Ravindranath return reset; 242089a36810SAnil Ravindranath } else if (pinstance->ioa_state == target_state) { 242189a36810SAnil Ravindranath reset = 0; 242289a36810SAnil Ravindranath } 242389a36810SAnil Ravindranath } 242489a36810SAnil Ravindranath 242589a36810SAnil Ravindranath if (reset) { 242689a36810SAnil Ravindranath pmcraid_info("reset_reload: proceeding with reset\n"); 242789a36810SAnil Ravindranath scsi_block_requests(pinstance->host); 242889a36810SAnil Ravindranath reset_cmd = pmcraid_get_free_cmd(pinstance); 242989a36810SAnil Ravindranath 243089a36810SAnil Ravindranath if (reset_cmd == NULL) { 243189a36810SAnil Ravindranath pmcraid_err("no free cmnd for reset_reload\n"); 243289a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 243389a36810SAnil Ravindranath lock_flags); 243489a36810SAnil Ravindranath return reset; 243589a36810SAnil Ravindranath } 243689a36810SAnil Ravindranath 243789a36810SAnil Ravindranath if (shutdown_type == SHUTDOWN_NORMAL) 243889a36810SAnil Ravindranath pinstance->ioa_bringdown = 1; 243989a36810SAnil Ravindranath 244089a36810SAnil Ravindranath pinstance->ioa_shutdown_type = shutdown_type; 244189a36810SAnil Ravindranath pinstance->reset_cmd = reset_cmd; 244289a36810SAnil Ravindranath pinstance->force_ioa_reset = reset; 244389a36810SAnil Ravindranath pmcraid_info("reset_reload: initiating reset\n"); 244489a36810SAnil Ravindranath pmcraid_ioa_reset(reset_cmd); 244589a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 244689a36810SAnil Ravindranath pmcraid_info("reset_reload: waiting for reset to complete\n"); 244789a36810SAnil Ravindranath wait_event(pinstance->reset_wait_q, 244889a36810SAnil Ravindranath !pinstance->ioa_reset_in_progress); 244989a36810SAnil Ravindranath 245089a36810SAnil Ravindranath pmcraid_info("reset_reload: reset is complete !!\n"); 245189a36810SAnil Ravindranath scsi_unblock_requests(pinstance->host); 245289a36810SAnil Ravindranath if (pinstance->ioa_state == target_state) 245389a36810SAnil Ravindranath reset = 0; 245489a36810SAnil Ravindranath } 245589a36810SAnil Ravindranath 245689a36810SAnil Ravindranath return reset; 245789a36810SAnil Ravindranath } 245889a36810SAnil Ravindranath 245989a36810SAnil Ravindranath /** 246089a36810SAnil Ravindranath * pmcraid_reset_bringdown - wrapper over pmcraid_reset_reload to bringdown IOA 246189a36810SAnil Ravindranath * 246289a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 246389a36810SAnil Ravindranath * 246489a36810SAnil Ravindranath * Return Value 246589a36810SAnil Ravindranath * whatever is returned from pmcraid_reset_reload 246689a36810SAnil Ravindranath */ 246789a36810SAnil Ravindranath static int pmcraid_reset_bringdown(struct pmcraid_instance *pinstance) 246889a36810SAnil Ravindranath { 246989a36810SAnil Ravindranath return pmcraid_reset_reload(pinstance, 247089a36810SAnil Ravindranath SHUTDOWN_NORMAL, 247189a36810SAnil Ravindranath IOA_STATE_UNKNOWN); 247289a36810SAnil Ravindranath } 247389a36810SAnil Ravindranath 247489a36810SAnil Ravindranath /** 247589a36810SAnil Ravindranath * pmcraid_reset_bringup - wrapper over pmcraid_reset_reload to bring up IOA 247689a36810SAnil Ravindranath * 247789a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 247889a36810SAnil Ravindranath * 247989a36810SAnil Ravindranath * Return Value 248089a36810SAnil Ravindranath * whatever is returned from pmcraid_reset_reload 248189a36810SAnil Ravindranath */ 248289a36810SAnil Ravindranath static int pmcraid_reset_bringup(struct pmcraid_instance *pinstance) 248389a36810SAnil Ravindranath { 2484c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, PMC_DEVICE_EVENT_RESET_START); 2485c20c4267SAnil Ravindranath 248689a36810SAnil Ravindranath return pmcraid_reset_reload(pinstance, 248789a36810SAnil Ravindranath SHUTDOWN_NONE, 248889a36810SAnil Ravindranath IOA_STATE_OPERATIONAL); 248989a36810SAnil Ravindranath } 249089a36810SAnil Ravindranath 249189a36810SAnil Ravindranath /** 249289a36810SAnil Ravindranath * pmcraid_request_sense - Send request sense to a device 249389a36810SAnil Ravindranath * @cmd: pmcraid command struct 249489a36810SAnil Ravindranath * 249589a36810SAnil Ravindranath * This function sends a request sense to a device as a result of a check 249689a36810SAnil Ravindranath * condition. This method re-uses the same command block that failed earlier. 249789a36810SAnil Ravindranath */ 249889a36810SAnil Ravindranath static void pmcraid_request_sense(struct pmcraid_cmd *cmd) 249989a36810SAnil Ravindranath { 250089a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 250189a36810SAnil Ravindranath struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; 250289a36810SAnil Ravindranath 250389a36810SAnil Ravindranath /* allocate DMAable memory for sense buffers */ 250489a36810SAnil Ravindranath cmd->sense_buffer = pci_alloc_consistent(cmd->drv_inst->pdev, 250589a36810SAnil Ravindranath SCSI_SENSE_BUFFERSIZE, 250689a36810SAnil Ravindranath &cmd->sense_buffer_dma); 250789a36810SAnil Ravindranath 250889a36810SAnil Ravindranath if (cmd->sense_buffer == NULL) { 250989a36810SAnil Ravindranath pmcraid_err 251089a36810SAnil Ravindranath ("couldn't allocate sense buffer for request sense\n"); 251189a36810SAnil Ravindranath pmcraid_erp_done(cmd); 251289a36810SAnil Ravindranath return; 251389a36810SAnil Ravindranath } 251489a36810SAnil Ravindranath 251589a36810SAnil Ravindranath /* re-use the command block */ 251689a36810SAnil Ravindranath memset(&cmd->ioa_cb->ioasa, 0, sizeof(struct pmcraid_ioasa)); 251789a36810SAnil Ravindranath memset(ioarcb->cdb, 0, PMCRAID_MAX_CDB_LEN); 251889a36810SAnil Ravindranath ioarcb->request_flags0 = (SYNC_COMPLETE | 251989a36810SAnil Ravindranath NO_LINK_DESCS | 252089a36810SAnil Ravindranath INHIBIT_UL_CHECK); 252189a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_SCSI; 252289a36810SAnil Ravindranath ioarcb->cdb[0] = REQUEST_SENSE; 252389a36810SAnil Ravindranath ioarcb->cdb[4] = SCSI_SENSE_BUFFERSIZE; 252489a36810SAnil Ravindranath 252589a36810SAnil Ravindranath ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + 252689a36810SAnil Ravindranath offsetof(struct pmcraid_ioarcb, 252789a36810SAnil Ravindranath add_data.u.ioadl[0])); 252889a36810SAnil Ravindranath ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); 252989a36810SAnil Ravindranath 253089a36810SAnil Ravindranath ioarcb->data_transfer_length = cpu_to_le32(SCSI_SENSE_BUFFERSIZE); 253189a36810SAnil Ravindranath 253289a36810SAnil Ravindranath ioadl->address = cpu_to_le64(cmd->sense_buffer_dma); 253389a36810SAnil Ravindranath ioadl->data_len = cpu_to_le32(SCSI_SENSE_BUFFERSIZE); 253488197966SAnil Ravindranath ioadl->flags = IOADL_FLAGS_LAST_DESC; 253589a36810SAnil Ravindranath 253689a36810SAnil Ravindranath /* request sense might be called as part of error response processing 253789a36810SAnil Ravindranath * which runs in tasklets context. It is possible that mid-layer might 253889a36810SAnil Ravindranath * schedule queuecommand during this time, hence, writting to IOARRIN 253989a36810SAnil Ravindranath * must be protect by host_lock 254089a36810SAnil Ravindranath */ 254189a36810SAnil Ravindranath pmcraid_send_cmd(cmd, pmcraid_erp_done, 254289a36810SAnil Ravindranath PMCRAID_REQUEST_SENSE_TIMEOUT, 254389a36810SAnil Ravindranath pmcraid_timeout_handler); 254489a36810SAnil Ravindranath } 254589a36810SAnil Ravindranath 254689a36810SAnil Ravindranath /** 254789a36810SAnil Ravindranath * pmcraid_cancel_all - cancel all outstanding IOARCBs as part of error recovery 254889a36810SAnil Ravindranath * @cmd: command that failed 254989a36810SAnil Ravindranath * @sense: true if request_sense is required after cancel all 255089a36810SAnil Ravindranath * 255189a36810SAnil Ravindranath * This function sends a cancel all to a device to clear the queue. 255289a36810SAnil Ravindranath */ 255389a36810SAnil Ravindranath static void pmcraid_cancel_all(struct pmcraid_cmd *cmd, u32 sense) 255489a36810SAnil Ravindranath { 255589a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; 255689a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 255789a36810SAnil Ravindranath struct pmcraid_resource_entry *res = scsi_cmd->device->hostdata; 255889a36810SAnil Ravindranath void (*cmd_done) (struct pmcraid_cmd *) = sense ? pmcraid_erp_done 255989a36810SAnil Ravindranath : pmcraid_request_sense; 256089a36810SAnil Ravindranath 256189a36810SAnil Ravindranath memset(ioarcb->cdb, 0, PMCRAID_MAX_CDB_LEN); 256289a36810SAnil Ravindranath ioarcb->request_flags0 = SYNC_OVERRIDE; 256389a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_IOACMD; 256489a36810SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_CANCEL_ALL_REQUESTS; 256589a36810SAnil Ravindranath 256689a36810SAnil Ravindranath if (RES_IS_GSCSI(res->cfg_entry)) 256789a36810SAnil Ravindranath ioarcb->cdb[1] = PMCRAID_SYNC_COMPLETE_AFTER_CANCEL; 256889a36810SAnil Ravindranath 256989a36810SAnil Ravindranath ioarcb->ioadl_bus_addr = 0; 257089a36810SAnil Ravindranath ioarcb->ioadl_length = 0; 257189a36810SAnil Ravindranath ioarcb->data_transfer_length = 0; 257289a36810SAnil Ravindranath ioarcb->ioarcb_bus_addr &= (~0x1FULL); 257389a36810SAnil Ravindranath 257489a36810SAnil Ravindranath /* writing to IOARRIN must be protected by host_lock, as mid-layer 257589a36810SAnil Ravindranath * schedule queuecommand while we are doing this 257689a36810SAnil Ravindranath */ 257789a36810SAnil Ravindranath pmcraid_send_cmd(cmd, cmd_done, 257889a36810SAnil Ravindranath PMCRAID_REQUEST_SENSE_TIMEOUT, 257989a36810SAnil Ravindranath pmcraid_timeout_handler); 258089a36810SAnil Ravindranath } 258189a36810SAnil Ravindranath 258289a36810SAnil Ravindranath /** 258389a36810SAnil Ravindranath * pmcraid_frame_auto_sense: frame fixed format sense information 258489a36810SAnil Ravindranath * 258589a36810SAnil Ravindranath * @cmd: pointer to failing command block 258689a36810SAnil Ravindranath * 258789a36810SAnil Ravindranath * Return value 258889a36810SAnil Ravindranath * none 258989a36810SAnil Ravindranath */ 259089a36810SAnil Ravindranath static void pmcraid_frame_auto_sense(struct pmcraid_cmd *cmd) 259189a36810SAnil Ravindranath { 259289a36810SAnil Ravindranath u8 *sense_buf = cmd->scsi_cmd->sense_buffer; 259389a36810SAnil Ravindranath struct pmcraid_resource_entry *res = cmd->scsi_cmd->device->hostdata; 259489a36810SAnil Ravindranath struct pmcraid_ioasa *ioasa = &cmd->ioa_cb->ioasa; 259589a36810SAnil Ravindranath u32 ioasc = le32_to_cpu(ioasa->ioasc); 259689a36810SAnil Ravindranath u32 failing_lba = 0; 259789a36810SAnil Ravindranath 259889a36810SAnil Ravindranath memset(sense_buf, 0, SCSI_SENSE_BUFFERSIZE); 259989a36810SAnil Ravindranath cmd->scsi_cmd->result = SAM_STAT_CHECK_CONDITION; 260089a36810SAnil Ravindranath 260189a36810SAnil Ravindranath if (RES_IS_VSET(res->cfg_entry) && 260289a36810SAnil Ravindranath ioasc == PMCRAID_IOASC_ME_READ_ERROR_NO_REALLOC && 260389a36810SAnil Ravindranath ioasa->u.vset.failing_lba_hi != 0) { 260489a36810SAnil Ravindranath 260589a36810SAnil Ravindranath sense_buf[0] = 0x72; 260689a36810SAnil Ravindranath sense_buf[1] = PMCRAID_IOASC_SENSE_KEY(ioasc); 260789a36810SAnil Ravindranath sense_buf[2] = PMCRAID_IOASC_SENSE_CODE(ioasc); 260889a36810SAnil Ravindranath sense_buf[3] = PMCRAID_IOASC_SENSE_QUAL(ioasc); 260989a36810SAnil Ravindranath 261089a36810SAnil Ravindranath sense_buf[7] = 12; 261189a36810SAnil Ravindranath sense_buf[8] = 0; 261289a36810SAnil Ravindranath sense_buf[9] = 0x0A; 261389a36810SAnil Ravindranath sense_buf[10] = 0x80; 261489a36810SAnil Ravindranath 261589a36810SAnil Ravindranath failing_lba = le32_to_cpu(ioasa->u.vset.failing_lba_hi); 261689a36810SAnil Ravindranath 261789a36810SAnil Ravindranath sense_buf[12] = (failing_lba & 0xff000000) >> 24; 261889a36810SAnil Ravindranath sense_buf[13] = (failing_lba & 0x00ff0000) >> 16; 261989a36810SAnil Ravindranath sense_buf[14] = (failing_lba & 0x0000ff00) >> 8; 262089a36810SAnil Ravindranath sense_buf[15] = failing_lba & 0x000000ff; 262189a36810SAnil Ravindranath 262289a36810SAnil Ravindranath failing_lba = le32_to_cpu(ioasa->u.vset.failing_lba_lo); 262389a36810SAnil Ravindranath 262489a36810SAnil Ravindranath sense_buf[16] = (failing_lba & 0xff000000) >> 24; 262589a36810SAnil Ravindranath sense_buf[17] = (failing_lba & 0x00ff0000) >> 16; 262689a36810SAnil Ravindranath sense_buf[18] = (failing_lba & 0x0000ff00) >> 8; 262789a36810SAnil Ravindranath sense_buf[19] = failing_lba & 0x000000ff; 262889a36810SAnil Ravindranath } else { 262989a36810SAnil Ravindranath sense_buf[0] = 0x70; 263089a36810SAnil Ravindranath sense_buf[2] = PMCRAID_IOASC_SENSE_KEY(ioasc); 263189a36810SAnil Ravindranath sense_buf[12] = PMCRAID_IOASC_SENSE_CODE(ioasc); 263289a36810SAnil Ravindranath sense_buf[13] = PMCRAID_IOASC_SENSE_QUAL(ioasc); 263389a36810SAnil Ravindranath 263489a36810SAnil Ravindranath if (ioasc == PMCRAID_IOASC_ME_READ_ERROR_NO_REALLOC) { 263589a36810SAnil Ravindranath if (RES_IS_VSET(res->cfg_entry)) 263689a36810SAnil Ravindranath failing_lba = 263789a36810SAnil Ravindranath le32_to_cpu(ioasa->u. 263889a36810SAnil Ravindranath vset.failing_lba_lo); 263989a36810SAnil Ravindranath sense_buf[0] |= 0x80; 264089a36810SAnil Ravindranath sense_buf[3] = (failing_lba >> 24) & 0xff; 264189a36810SAnil Ravindranath sense_buf[4] = (failing_lba >> 16) & 0xff; 264289a36810SAnil Ravindranath sense_buf[5] = (failing_lba >> 8) & 0xff; 264389a36810SAnil Ravindranath sense_buf[6] = failing_lba & 0xff; 264489a36810SAnil Ravindranath } 264589a36810SAnil Ravindranath 264689a36810SAnil Ravindranath sense_buf[7] = 6; /* additional length */ 264789a36810SAnil Ravindranath } 264889a36810SAnil Ravindranath } 264989a36810SAnil Ravindranath 265089a36810SAnil Ravindranath /** 265189a36810SAnil Ravindranath * pmcraid_error_handler - Error response handlers for a SCSI op 265289a36810SAnil Ravindranath * @cmd: pointer to pmcraid_cmd that has failed 265389a36810SAnil Ravindranath * 265489a36810SAnil Ravindranath * This function determines whether or not to initiate ERP on the affected 265589a36810SAnil Ravindranath * device. This is called from a tasklet, which doesn't hold any locks. 265689a36810SAnil Ravindranath * 265789a36810SAnil Ravindranath * Return value: 265889a36810SAnil Ravindranath * 0 it caller can complete the request, otherwise 1 where in error 265989a36810SAnil Ravindranath * handler itself completes the request and returns the command block 266089a36810SAnil Ravindranath * back to free-pool 266189a36810SAnil Ravindranath */ 266289a36810SAnil Ravindranath static int pmcraid_error_handler(struct pmcraid_cmd *cmd) 266389a36810SAnil Ravindranath { 266489a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; 266589a36810SAnil Ravindranath struct pmcraid_resource_entry *res = scsi_cmd->device->hostdata; 266689a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 266789a36810SAnil Ravindranath struct pmcraid_ioasa *ioasa = &cmd->ioa_cb->ioasa; 266889a36810SAnil Ravindranath u32 ioasc = le32_to_cpu(ioasa->ioasc); 266989a36810SAnil Ravindranath u32 masked_ioasc = ioasc & PMCRAID_IOASC_SENSE_MASK; 267089a36810SAnil Ravindranath u32 sense_copied = 0; 267189a36810SAnil Ravindranath 267289a36810SAnil Ravindranath if (!res) { 267389a36810SAnil Ravindranath pmcraid_info("resource pointer is NULL\n"); 267489a36810SAnil Ravindranath return 0; 267589a36810SAnil Ravindranath } 267689a36810SAnil Ravindranath 267789a36810SAnil Ravindranath /* If this was a SCSI read/write command keep count of errors */ 267889a36810SAnil Ravindranath if (SCSI_CMD_TYPE(scsi_cmd->cmnd[0]) == SCSI_READ_CMD) 267989a36810SAnil Ravindranath atomic_inc(&res->read_failures); 268089a36810SAnil Ravindranath else if (SCSI_CMD_TYPE(scsi_cmd->cmnd[0]) == SCSI_WRITE_CMD) 268189a36810SAnil Ravindranath atomic_inc(&res->write_failures); 268289a36810SAnil Ravindranath 268389a36810SAnil Ravindranath if (!RES_IS_GSCSI(res->cfg_entry) && 268489a36810SAnil Ravindranath masked_ioasc != PMCRAID_IOASC_HW_DEVICE_BUS_STATUS_ERROR) { 268589a36810SAnil Ravindranath pmcraid_frame_auto_sense(cmd); 268689a36810SAnil Ravindranath } 268789a36810SAnil Ravindranath 268889a36810SAnil Ravindranath /* Log IOASC/IOASA information based on user settings */ 268989a36810SAnil Ravindranath pmcraid_ioasc_logger(ioasc, cmd); 269089a36810SAnil Ravindranath 269189a36810SAnil Ravindranath switch (masked_ioasc) { 269289a36810SAnil Ravindranath 269389a36810SAnil Ravindranath case PMCRAID_IOASC_AC_TERMINATED_BY_HOST: 269489a36810SAnil Ravindranath scsi_cmd->result |= (DID_ABORT << 16); 269589a36810SAnil Ravindranath break; 269689a36810SAnil Ravindranath 269789a36810SAnil Ravindranath case PMCRAID_IOASC_IR_INVALID_RESOURCE_HANDLE: 269889a36810SAnil Ravindranath case PMCRAID_IOASC_HW_CANNOT_COMMUNICATE: 269989a36810SAnil Ravindranath scsi_cmd->result |= (DID_NO_CONNECT << 16); 270089a36810SAnil Ravindranath break; 270189a36810SAnil Ravindranath 270289a36810SAnil Ravindranath case PMCRAID_IOASC_NR_SYNC_REQUIRED: 270389a36810SAnil Ravindranath res->sync_reqd = 1; 270489a36810SAnil Ravindranath scsi_cmd->result |= (DID_IMM_RETRY << 16); 270589a36810SAnil Ravindranath break; 270689a36810SAnil Ravindranath 270789a36810SAnil Ravindranath case PMCRAID_IOASC_ME_READ_ERROR_NO_REALLOC: 270889a36810SAnil Ravindranath scsi_cmd->result |= (DID_PASSTHROUGH << 16); 270989a36810SAnil Ravindranath break; 271089a36810SAnil Ravindranath 271189a36810SAnil Ravindranath case PMCRAID_IOASC_UA_BUS_WAS_RESET: 271289a36810SAnil Ravindranath case PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER: 271389a36810SAnil Ravindranath if (!res->reset_progress) 271489a36810SAnil Ravindranath scsi_report_bus_reset(pinstance->host, 271589a36810SAnil Ravindranath scsi_cmd->device->channel); 271689a36810SAnil Ravindranath scsi_cmd->result |= (DID_ERROR << 16); 271789a36810SAnil Ravindranath break; 271889a36810SAnil Ravindranath 271989a36810SAnil Ravindranath case PMCRAID_IOASC_HW_DEVICE_BUS_STATUS_ERROR: 272089a36810SAnil Ravindranath scsi_cmd->result |= PMCRAID_IOASC_SENSE_STATUS(ioasc); 272189a36810SAnil Ravindranath res->sync_reqd = 1; 272289a36810SAnil Ravindranath 272389a36810SAnil Ravindranath /* if check_condition is not active return with error otherwise 272489a36810SAnil Ravindranath * get/frame the sense buffer 272589a36810SAnil Ravindranath */ 272689a36810SAnil Ravindranath if (PMCRAID_IOASC_SENSE_STATUS(ioasc) != 272789a36810SAnil Ravindranath SAM_STAT_CHECK_CONDITION && 272889a36810SAnil Ravindranath PMCRAID_IOASC_SENSE_STATUS(ioasc) != SAM_STAT_ACA_ACTIVE) 272989a36810SAnil Ravindranath return 0; 273089a36810SAnil Ravindranath 273189a36810SAnil Ravindranath /* If we have auto sense data as part of IOASA pass it to 273289a36810SAnil Ravindranath * mid-layer 273389a36810SAnil Ravindranath */ 273489a36810SAnil Ravindranath if (ioasa->auto_sense_length != 0) { 273589a36810SAnil Ravindranath short sense_len = ioasa->auto_sense_length; 273689a36810SAnil Ravindranath int data_size = min_t(u16, le16_to_cpu(sense_len), 273789a36810SAnil Ravindranath SCSI_SENSE_BUFFERSIZE); 273889a36810SAnil Ravindranath 273989a36810SAnil Ravindranath memcpy(scsi_cmd->sense_buffer, 274089a36810SAnil Ravindranath ioasa->sense_data, 274189a36810SAnil Ravindranath data_size); 274289a36810SAnil Ravindranath sense_copied = 1; 274389a36810SAnil Ravindranath } 274489a36810SAnil Ravindranath 2745a70757baSAnil Ravindranath if (RES_IS_GSCSI(res->cfg_entry)) 274689a36810SAnil Ravindranath pmcraid_cancel_all(cmd, sense_copied); 2747a70757baSAnil Ravindranath else if (sense_copied) 274889a36810SAnil Ravindranath pmcraid_erp_done(cmd); 2749a70757baSAnil Ravindranath else 275089a36810SAnil Ravindranath pmcraid_request_sense(cmd); 275189a36810SAnil Ravindranath 275289a36810SAnil Ravindranath return 1; 275389a36810SAnil Ravindranath 275489a36810SAnil Ravindranath case PMCRAID_IOASC_NR_INIT_CMD_REQUIRED: 275589a36810SAnil Ravindranath break; 275689a36810SAnil Ravindranath 275789a36810SAnil Ravindranath default: 275889a36810SAnil Ravindranath if (PMCRAID_IOASC_SENSE_KEY(ioasc) > RECOVERED_ERROR) 275989a36810SAnil Ravindranath scsi_cmd->result |= (DID_ERROR << 16); 276089a36810SAnil Ravindranath break; 276189a36810SAnil Ravindranath } 276289a36810SAnil Ravindranath return 0; 276389a36810SAnil Ravindranath } 276489a36810SAnil Ravindranath 276589a36810SAnil Ravindranath /** 276689a36810SAnil Ravindranath * pmcraid_reset_device - device reset handler functions 276789a36810SAnil Ravindranath * 276889a36810SAnil Ravindranath * @scsi_cmd: scsi command struct 276989a36810SAnil Ravindranath * @modifier: reset modifier indicating the reset sequence to be performed 277089a36810SAnil Ravindranath * 277189a36810SAnil Ravindranath * This function issues a device reset to the affected device. 277289a36810SAnil Ravindranath * A LUN reset will be sent to the device first. If that does 277389a36810SAnil Ravindranath * not work, a target reset will be sent. 277489a36810SAnil Ravindranath * 277589a36810SAnil Ravindranath * Return value: 277689a36810SAnil Ravindranath * SUCCESS / FAILED 277789a36810SAnil Ravindranath */ 277889a36810SAnil Ravindranath static int pmcraid_reset_device( 277989a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd, 278089a36810SAnil Ravindranath unsigned long timeout, 278189a36810SAnil Ravindranath u8 modifier 278289a36810SAnil Ravindranath ) 278389a36810SAnil Ravindranath { 278489a36810SAnil Ravindranath struct pmcraid_cmd *cmd; 278589a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 278689a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 278789a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb; 278889a36810SAnil Ravindranath unsigned long lock_flags; 278989a36810SAnil Ravindranath u32 ioasc; 279089a36810SAnil Ravindranath 279189a36810SAnil Ravindranath pinstance = 279289a36810SAnil Ravindranath (struct pmcraid_instance *)scsi_cmd->device->host->hostdata; 279389a36810SAnil Ravindranath res = scsi_cmd->device->hostdata; 279489a36810SAnil Ravindranath 279589a36810SAnil Ravindranath if (!res) { 279634876402SAnil Ravindranath sdev_printk(KERN_ERR, scsi_cmd->device, 279734876402SAnil Ravindranath "reset_device: NULL resource pointer\n"); 279889a36810SAnil Ravindranath return FAILED; 279989a36810SAnil Ravindranath } 280089a36810SAnil Ravindranath 280189a36810SAnil Ravindranath /* If adapter is currently going through reset/reload, return failed. 280289a36810SAnil Ravindranath * This will force the mid-layer to call _eh_bus/host reset, which 280389a36810SAnil Ravindranath * will then go to sleep and wait for the reset to complete 280489a36810SAnil Ravindranath */ 280589a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 280689a36810SAnil Ravindranath if (pinstance->ioa_reset_in_progress || 280789a36810SAnil Ravindranath pinstance->ioa_state == IOA_STATE_DEAD) { 280889a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 280989a36810SAnil Ravindranath return FAILED; 281089a36810SAnil Ravindranath } 281189a36810SAnil Ravindranath 281289a36810SAnil Ravindranath res->reset_progress = 1; 281389a36810SAnil Ravindranath pmcraid_info("Resetting %s resource with addr %x\n", 281489a36810SAnil Ravindranath ((modifier & RESET_DEVICE_LUN) ? "LUN" : 281589a36810SAnil Ravindranath ((modifier & RESET_DEVICE_TARGET) ? "TARGET" : "BUS")), 281689a36810SAnil Ravindranath le32_to_cpu(res->cfg_entry.resource_address)); 281789a36810SAnil Ravindranath 281889a36810SAnil Ravindranath /* get a free cmd block */ 281989a36810SAnil Ravindranath cmd = pmcraid_get_free_cmd(pinstance); 282089a36810SAnil Ravindranath 282189a36810SAnil Ravindranath if (cmd == NULL) { 282289a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 282389a36810SAnil Ravindranath pmcraid_err("%s: no cmd blocks are available\n", __func__); 282489a36810SAnil Ravindranath return FAILED; 282589a36810SAnil Ravindranath } 282689a36810SAnil Ravindranath 282789a36810SAnil Ravindranath ioarcb = &cmd->ioa_cb->ioarcb; 282889a36810SAnil Ravindranath ioarcb->resource_handle = res->cfg_entry.resource_handle; 282989a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_IOACMD; 283089a36810SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_RESET_DEVICE; 283189a36810SAnil Ravindranath 283289a36810SAnil Ravindranath /* Initialize reset modifier bits */ 283389a36810SAnil Ravindranath if (modifier) 283489a36810SAnil Ravindranath modifier = ENABLE_RESET_MODIFIER | modifier; 283589a36810SAnil Ravindranath 283689a36810SAnil Ravindranath ioarcb->cdb[1] = modifier; 283789a36810SAnil Ravindranath 283889a36810SAnil Ravindranath init_completion(&cmd->wait_for_completion); 283989a36810SAnil Ravindranath cmd->completion_req = 1; 284089a36810SAnil Ravindranath 284189a36810SAnil Ravindranath pmcraid_info("cmd(CDB[0] = %x) for %x with index = %d\n", 284289a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 284389a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioarcb.resource_handle), 284489a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle) >> 2); 284589a36810SAnil Ravindranath 284689a36810SAnil Ravindranath pmcraid_send_cmd(cmd, 284789a36810SAnil Ravindranath pmcraid_internal_done, 284889a36810SAnil Ravindranath timeout, 284989a36810SAnil Ravindranath pmcraid_timeout_handler); 285089a36810SAnil Ravindranath 285189a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 285289a36810SAnil Ravindranath 285389a36810SAnil Ravindranath /* RESET_DEVICE command completes after all pending IOARCBs are 285489a36810SAnil Ravindranath * completed. Once this command is completed, pmcraind_internal_done 285589a36810SAnil Ravindranath * will wake up the 'completion' queue. 285689a36810SAnil Ravindranath */ 285789a36810SAnil Ravindranath wait_for_completion(&cmd->wait_for_completion); 285889a36810SAnil Ravindranath 285989a36810SAnil Ravindranath /* complete the command here itself and return the command block 286089a36810SAnil Ravindranath * to free list 286189a36810SAnil Ravindranath */ 286289a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 286389a36810SAnil Ravindranath res->reset_progress = 0; 286489a36810SAnil Ravindranath ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); 286589a36810SAnil Ravindranath 286689a36810SAnil Ravindranath /* set the return value based on the returned ioasc */ 286789a36810SAnil Ravindranath return PMCRAID_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS; 286889a36810SAnil Ravindranath } 286989a36810SAnil Ravindranath 287089a36810SAnil Ravindranath /** 287189a36810SAnil Ravindranath * _pmcraid_io_done - helper for pmcraid_io_done function 287289a36810SAnil Ravindranath * 287389a36810SAnil Ravindranath * @cmd: pointer to pmcraid command struct 287489a36810SAnil Ravindranath * @reslen: residual data length to be set in the ioasa 287589a36810SAnil Ravindranath * @ioasc: ioasc either returned by IOA or set by driver itself. 287689a36810SAnil Ravindranath * 287789a36810SAnil Ravindranath * This function is invoked by pmcraid_io_done to complete mid-layer 287889a36810SAnil Ravindranath * scsi ops. 287989a36810SAnil Ravindranath * 288089a36810SAnil Ravindranath * Return value: 288189a36810SAnil Ravindranath * 0 if caller is required to return it to free_pool. Returns 1 if 288289a36810SAnil Ravindranath * caller need not worry about freeing command block as error handler 288389a36810SAnil Ravindranath * will take care of that. 288489a36810SAnil Ravindranath */ 288589a36810SAnil Ravindranath 288689a36810SAnil Ravindranath static int _pmcraid_io_done(struct pmcraid_cmd *cmd, int reslen, int ioasc) 288789a36810SAnil Ravindranath { 288889a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; 288989a36810SAnil Ravindranath int rc = 0; 289089a36810SAnil Ravindranath 289189a36810SAnil Ravindranath scsi_set_resid(scsi_cmd, reslen); 289289a36810SAnil Ravindranath 289389a36810SAnil Ravindranath pmcraid_info("response(%d) CDB[0] = %x ioasc:result: %x:%x\n", 289489a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle) >> 2, 289589a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 289689a36810SAnil Ravindranath ioasc, scsi_cmd->result); 289789a36810SAnil Ravindranath 289889a36810SAnil Ravindranath if (PMCRAID_IOASC_SENSE_KEY(ioasc) != 0) 289989a36810SAnil Ravindranath rc = pmcraid_error_handler(cmd); 290089a36810SAnil Ravindranath 290189a36810SAnil Ravindranath if (rc == 0) { 290289a36810SAnil Ravindranath scsi_dma_unmap(scsi_cmd); 290389a36810SAnil Ravindranath scsi_cmd->scsi_done(scsi_cmd); 290489a36810SAnil Ravindranath } 290589a36810SAnil Ravindranath 290689a36810SAnil Ravindranath return rc; 290789a36810SAnil Ravindranath } 290889a36810SAnil Ravindranath 290989a36810SAnil Ravindranath /** 291089a36810SAnil Ravindranath * pmcraid_io_done - SCSI completion function 291189a36810SAnil Ravindranath * 291289a36810SAnil Ravindranath * @cmd: pointer to pmcraid command struct 291389a36810SAnil Ravindranath * 291489a36810SAnil Ravindranath * This function is invoked by tasklet/mid-layer error handler to completing 291589a36810SAnil Ravindranath * the SCSI ops sent from mid-layer. 291689a36810SAnil Ravindranath * 291789a36810SAnil Ravindranath * Return value 291889a36810SAnil Ravindranath * none 291989a36810SAnil Ravindranath */ 292089a36810SAnil Ravindranath 292189a36810SAnil Ravindranath static void pmcraid_io_done(struct pmcraid_cmd *cmd) 292289a36810SAnil Ravindranath { 292389a36810SAnil Ravindranath u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); 292489a36810SAnil Ravindranath u32 reslen = le32_to_cpu(cmd->ioa_cb->ioasa.residual_data_length); 292589a36810SAnil Ravindranath 292689a36810SAnil Ravindranath if (_pmcraid_io_done(cmd, reslen, ioasc) == 0) 292789a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 292889a36810SAnil Ravindranath } 292989a36810SAnil Ravindranath 293089a36810SAnil Ravindranath /** 293189a36810SAnil Ravindranath * pmcraid_abort_cmd - Aborts a single IOARCB already submitted to IOA 293289a36810SAnil Ravindranath * 293389a36810SAnil Ravindranath * @cmd: command block of the command to be aborted 293489a36810SAnil Ravindranath * 293589a36810SAnil Ravindranath * Return Value: 293689a36810SAnil Ravindranath * returns pointer to command structure used as cancelling cmd 293789a36810SAnil Ravindranath */ 293889a36810SAnil Ravindranath static struct pmcraid_cmd *pmcraid_abort_cmd(struct pmcraid_cmd *cmd) 293989a36810SAnil Ravindranath { 294089a36810SAnil Ravindranath struct pmcraid_cmd *cancel_cmd; 294189a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 294289a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 294389a36810SAnil Ravindranath 294489a36810SAnil Ravindranath pinstance = (struct pmcraid_instance *)cmd->drv_inst; 294589a36810SAnil Ravindranath res = cmd->scsi_cmd->device->hostdata; 294689a36810SAnil Ravindranath 294789a36810SAnil Ravindranath cancel_cmd = pmcraid_get_free_cmd(pinstance); 294889a36810SAnil Ravindranath 294989a36810SAnil Ravindranath if (cancel_cmd == NULL) { 295089a36810SAnil Ravindranath pmcraid_err("%s: no cmd blocks are available\n", __func__); 295189a36810SAnil Ravindranath return NULL; 295289a36810SAnil Ravindranath } 295389a36810SAnil Ravindranath 295489a36810SAnil Ravindranath pmcraid_prepare_cancel_cmd(cancel_cmd, cmd); 295589a36810SAnil Ravindranath 295689a36810SAnil Ravindranath pmcraid_info("aborting command CDB[0]= %x with index = %d\n", 295789a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 295889a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.response_handle >> 2); 295989a36810SAnil Ravindranath 296089a36810SAnil Ravindranath init_completion(&cancel_cmd->wait_for_completion); 296189a36810SAnil Ravindranath cancel_cmd->completion_req = 1; 296289a36810SAnil Ravindranath 296389a36810SAnil Ravindranath pmcraid_info("command (%d) CDB[0] = %x for %x\n", 296489a36810SAnil Ravindranath le32_to_cpu(cancel_cmd->ioa_cb->ioarcb.response_handle) >> 2, 2965c20c4267SAnil Ravindranath cancel_cmd->ioa_cb->ioarcb.cdb[0], 296689a36810SAnil Ravindranath le32_to_cpu(cancel_cmd->ioa_cb->ioarcb.resource_handle)); 296789a36810SAnil Ravindranath 296889a36810SAnil Ravindranath pmcraid_send_cmd(cancel_cmd, 296989a36810SAnil Ravindranath pmcraid_internal_done, 297089a36810SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, 297189a36810SAnil Ravindranath pmcraid_timeout_handler); 297289a36810SAnil Ravindranath return cancel_cmd; 297389a36810SAnil Ravindranath } 297489a36810SAnil Ravindranath 297589a36810SAnil Ravindranath /** 297689a36810SAnil Ravindranath * pmcraid_abort_complete - Waits for ABORT TASK completion 297789a36810SAnil Ravindranath * 297889a36810SAnil Ravindranath * @cancel_cmd: command block use as cancelling command 297989a36810SAnil Ravindranath * 298089a36810SAnil Ravindranath * Return Value: 298189a36810SAnil Ravindranath * returns SUCCESS if ABORT TASK has good completion 298289a36810SAnil Ravindranath * otherwise FAILED 298389a36810SAnil Ravindranath */ 298489a36810SAnil Ravindranath static int pmcraid_abort_complete(struct pmcraid_cmd *cancel_cmd) 298589a36810SAnil Ravindranath { 298689a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 298789a36810SAnil Ravindranath u32 ioasc; 298889a36810SAnil Ravindranath 298989a36810SAnil Ravindranath wait_for_completion(&cancel_cmd->wait_for_completion); 2990c20c4267SAnil Ravindranath res = cancel_cmd->res; 2991c20c4267SAnil Ravindranath cancel_cmd->res = NULL; 299289a36810SAnil Ravindranath ioasc = le32_to_cpu(cancel_cmd->ioa_cb->ioasa.ioasc); 299389a36810SAnil Ravindranath 299489a36810SAnil Ravindranath /* If the abort task is not timed out we will get a Good completion 299589a36810SAnil Ravindranath * as sense_key, otherwise we may get one the following responses 299625985edcSLucas De Marchi * due to subsequent bus reset or device reset. In case IOASC is 299789a36810SAnil Ravindranath * NR_SYNC_REQUIRED, set sync_reqd flag for the corresponding resource 299889a36810SAnil Ravindranath */ 299989a36810SAnil Ravindranath if (ioasc == PMCRAID_IOASC_UA_BUS_WAS_RESET || 300089a36810SAnil Ravindranath ioasc == PMCRAID_IOASC_NR_SYNC_REQUIRED) { 300189a36810SAnil Ravindranath if (ioasc == PMCRAID_IOASC_NR_SYNC_REQUIRED) 300289a36810SAnil Ravindranath res->sync_reqd = 1; 300389a36810SAnil Ravindranath ioasc = 0; 300489a36810SAnil Ravindranath } 300589a36810SAnil Ravindranath 300689a36810SAnil Ravindranath /* complete the command here itself */ 300789a36810SAnil Ravindranath pmcraid_return_cmd(cancel_cmd); 300889a36810SAnil Ravindranath return PMCRAID_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS; 300989a36810SAnil Ravindranath } 301089a36810SAnil Ravindranath 301189a36810SAnil Ravindranath /** 301289a36810SAnil Ravindranath * pmcraid_eh_abort_handler - entry point for aborting a single task on errors 301389a36810SAnil Ravindranath * 301489a36810SAnil Ravindranath * @scsi_cmd: scsi command struct given by mid-layer. When this is called 301589a36810SAnil Ravindranath * mid-layer ensures that no other commands are queued. This 301689a36810SAnil Ravindranath * never gets called under interrupt, but a separate eh thread. 301789a36810SAnil Ravindranath * 301889a36810SAnil Ravindranath * Return value: 301989a36810SAnil Ravindranath * SUCCESS / FAILED 302089a36810SAnil Ravindranath */ 302189a36810SAnil Ravindranath static int pmcraid_eh_abort_handler(struct scsi_cmnd *scsi_cmd) 302289a36810SAnil Ravindranath { 302389a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 302489a36810SAnil Ravindranath struct pmcraid_cmd *cmd; 302589a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 302689a36810SAnil Ravindranath unsigned long host_lock_flags; 302789a36810SAnil Ravindranath unsigned long pending_lock_flags; 302889a36810SAnil Ravindranath struct pmcraid_cmd *cancel_cmd = NULL; 302989a36810SAnil Ravindranath int cmd_found = 0; 303089a36810SAnil Ravindranath int rc = FAILED; 303189a36810SAnil Ravindranath 303289a36810SAnil Ravindranath pinstance = 303389a36810SAnil Ravindranath (struct pmcraid_instance *)scsi_cmd->device->host->hostdata; 303489a36810SAnil Ravindranath 303534876402SAnil Ravindranath scmd_printk(KERN_INFO, scsi_cmd, 303689a36810SAnil Ravindranath "I/O command timed out, aborting it.\n"); 303789a36810SAnil Ravindranath 303889a36810SAnil Ravindranath res = scsi_cmd->device->hostdata; 303989a36810SAnil Ravindranath 304089a36810SAnil Ravindranath if (res == NULL) 304189a36810SAnil Ravindranath return rc; 304289a36810SAnil Ravindranath 304389a36810SAnil Ravindranath /* If we are currently going through reset/reload, return failed. 304489a36810SAnil Ravindranath * This will force the mid-layer to eventually call 304589a36810SAnil Ravindranath * pmcraid_eh_host_reset which will then go to sleep and wait for the 304689a36810SAnil Ravindranath * reset to complete 304789a36810SAnil Ravindranath */ 304889a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, host_lock_flags); 304989a36810SAnil Ravindranath 305089a36810SAnil Ravindranath if (pinstance->ioa_reset_in_progress || 305189a36810SAnil Ravindranath pinstance->ioa_state == IOA_STATE_DEAD) { 305289a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 305389a36810SAnil Ravindranath host_lock_flags); 305489a36810SAnil Ravindranath return rc; 305589a36810SAnil Ravindranath } 305689a36810SAnil Ravindranath 305789a36810SAnil Ravindranath /* loop over pending cmd list to find cmd corresponding to this 305889a36810SAnil Ravindranath * scsi_cmd. Note that this command might not have been completed 305989a36810SAnil Ravindranath * already. locking: all pending commands are protected with 306089a36810SAnil Ravindranath * pending_pool_lock. 306189a36810SAnil Ravindranath */ 306289a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->pending_pool_lock, pending_lock_flags); 306389a36810SAnil Ravindranath list_for_each_entry(cmd, &pinstance->pending_cmd_pool, free_list) { 306489a36810SAnil Ravindranath 306589a36810SAnil Ravindranath if (cmd->scsi_cmd == scsi_cmd) { 306689a36810SAnil Ravindranath cmd_found = 1; 306789a36810SAnil Ravindranath break; 306889a36810SAnil Ravindranath } 306989a36810SAnil Ravindranath } 307089a36810SAnil Ravindranath 307189a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->pending_pool_lock, 307289a36810SAnil Ravindranath pending_lock_flags); 307389a36810SAnil Ravindranath 307489a36810SAnil Ravindranath /* If the command to be aborted was given to IOA and still pending with 307589a36810SAnil Ravindranath * it, send ABORT_TASK to abort this and wait for its completion 307689a36810SAnil Ravindranath */ 307789a36810SAnil Ravindranath if (cmd_found) 307889a36810SAnil Ravindranath cancel_cmd = pmcraid_abort_cmd(cmd); 307989a36810SAnil Ravindranath 308089a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 308189a36810SAnil Ravindranath host_lock_flags); 308289a36810SAnil Ravindranath 308389a36810SAnil Ravindranath if (cancel_cmd) { 3084c20c4267SAnil Ravindranath cancel_cmd->res = cmd->scsi_cmd->device->hostdata; 308589a36810SAnil Ravindranath rc = pmcraid_abort_complete(cancel_cmd); 308689a36810SAnil Ravindranath } 308789a36810SAnil Ravindranath 308889a36810SAnil Ravindranath return cmd_found ? rc : SUCCESS; 308989a36810SAnil Ravindranath } 309089a36810SAnil Ravindranath 309189a36810SAnil Ravindranath /** 309289a36810SAnil Ravindranath * pmcraid_eh_xxxx_reset_handler - bus/target/device reset handler callbacks 309389a36810SAnil Ravindranath * 309489a36810SAnil Ravindranath * @scmd: pointer to scsi_cmd that was sent to the resource to be reset. 309589a36810SAnil Ravindranath * 309689a36810SAnil Ravindranath * All these routines invokve pmcraid_reset_device with appropriate parameters. 309789a36810SAnil Ravindranath * Since these are called from mid-layer EH thread, no other IO will be queued 309889a36810SAnil Ravindranath * to the resource being reset. However, control path (IOCTL) may be active so 309989a36810SAnil Ravindranath * it is necessary to synchronize IOARRIN writes which pmcraid_reset_device 310089a36810SAnil Ravindranath * takes care by locking/unlocking host_lock. 310189a36810SAnil Ravindranath * 310289a36810SAnil Ravindranath * Return value 310389a36810SAnil Ravindranath * SUCCESS or FAILED 310489a36810SAnil Ravindranath */ 310589a36810SAnil Ravindranath static int pmcraid_eh_device_reset_handler(struct scsi_cmnd *scmd) 310689a36810SAnil Ravindranath { 310734876402SAnil Ravindranath scmd_printk(KERN_INFO, scmd, 310834876402SAnil Ravindranath "resetting device due to an I/O command timeout.\n"); 310989a36810SAnil Ravindranath return pmcraid_reset_device(scmd, 311089a36810SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, 311189a36810SAnil Ravindranath RESET_DEVICE_LUN); 311289a36810SAnil Ravindranath } 311389a36810SAnil Ravindranath 311489a36810SAnil Ravindranath static int pmcraid_eh_bus_reset_handler(struct scsi_cmnd *scmd) 311589a36810SAnil Ravindranath { 311634876402SAnil Ravindranath scmd_printk(KERN_INFO, scmd, 311734876402SAnil Ravindranath "Doing bus reset due to an I/O command timeout.\n"); 311889a36810SAnil Ravindranath return pmcraid_reset_device(scmd, 311989a36810SAnil Ravindranath PMCRAID_RESET_BUS_TIMEOUT, 312089a36810SAnil Ravindranath RESET_DEVICE_BUS); 312189a36810SAnil Ravindranath } 312289a36810SAnil Ravindranath 312389a36810SAnil Ravindranath static int pmcraid_eh_target_reset_handler(struct scsi_cmnd *scmd) 312489a36810SAnil Ravindranath { 312534876402SAnil Ravindranath scmd_printk(KERN_INFO, scmd, 312634876402SAnil Ravindranath "Doing target reset due to an I/O command timeout.\n"); 312789a36810SAnil Ravindranath return pmcraid_reset_device(scmd, 312889a36810SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, 312989a36810SAnil Ravindranath RESET_DEVICE_TARGET); 313089a36810SAnil Ravindranath } 313189a36810SAnil Ravindranath 313289a36810SAnil Ravindranath /** 313389a36810SAnil Ravindranath * pmcraid_eh_host_reset_handler - adapter reset handler callback 313489a36810SAnil Ravindranath * 313589a36810SAnil Ravindranath * @scmd: pointer to scsi_cmd that was sent to a resource of adapter 313689a36810SAnil Ravindranath * 313789a36810SAnil Ravindranath * Initiates adapter reset to bring it up to operational state 313889a36810SAnil Ravindranath * 313989a36810SAnil Ravindranath * Return value 314089a36810SAnil Ravindranath * SUCCESS or FAILED 314189a36810SAnil Ravindranath */ 314289a36810SAnil Ravindranath static int pmcraid_eh_host_reset_handler(struct scsi_cmnd *scmd) 314389a36810SAnil Ravindranath { 314489a36810SAnil Ravindranath unsigned long interval = 10000; /* 10 seconds interval */ 314589a36810SAnil Ravindranath int waits = jiffies_to_msecs(PMCRAID_RESET_HOST_TIMEOUT) / interval; 314689a36810SAnil Ravindranath struct pmcraid_instance *pinstance = 314789a36810SAnil Ravindranath (struct pmcraid_instance *)(scmd->device->host->hostdata); 314889a36810SAnil Ravindranath 314989a36810SAnil Ravindranath 315089a36810SAnil Ravindranath /* wait for an additional 150 seconds just in case firmware could come 315189a36810SAnil Ravindranath * up and if it could complete all the pending commands excluding the 315289a36810SAnil Ravindranath * two HCAM (CCN and LDN). 315389a36810SAnil Ravindranath */ 315489a36810SAnil Ravindranath while (waits--) { 315589a36810SAnil Ravindranath if (atomic_read(&pinstance->outstanding_cmds) <= 315689a36810SAnil Ravindranath PMCRAID_MAX_HCAM_CMD) 315789a36810SAnil Ravindranath return SUCCESS; 315889a36810SAnil Ravindranath msleep(interval); 315989a36810SAnil Ravindranath } 316089a36810SAnil Ravindranath 316189a36810SAnil Ravindranath dev_err(&pinstance->pdev->dev, 316289a36810SAnil Ravindranath "Adapter being reset due to an I/O command timeout.\n"); 316389a36810SAnil Ravindranath return pmcraid_reset_bringup(pinstance) == 0 ? SUCCESS : FAILED; 316489a36810SAnil Ravindranath } 316589a36810SAnil Ravindranath 316689a36810SAnil Ravindranath /** 316789a36810SAnil Ravindranath * pmcraid_task_attributes - Translate SPI Q-Tags to task attributes 316889a36810SAnil Ravindranath * @scsi_cmd: scsi command struct 316989a36810SAnil Ravindranath * 317089a36810SAnil Ravindranath * Return value 317189a36810SAnil Ravindranath * number of tags or 0 if the task is not tagged 317289a36810SAnil Ravindranath */ 317389a36810SAnil Ravindranath static u8 pmcraid_task_attributes(struct scsi_cmnd *scsi_cmd) 317489a36810SAnil Ravindranath { 317589a36810SAnil Ravindranath char tag[2]; 317689a36810SAnil Ravindranath u8 rc = 0; 317789a36810SAnil Ravindranath 317889a36810SAnil Ravindranath if (scsi_populate_tag_msg(scsi_cmd, tag)) { 317989a36810SAnil Ravindranath switch (tag[0]) { 318089a36810SAnil Ravindranath case MSG_SIMPLE_TAG: 318189a36810SAnil Ravindranath rc = TASK_TAG_SIMPLE; 318289a36810SAnil Ravindranath break; 318389a36810SAnil Ravindranath case MSG_HEAD_TAG: 318489a36810SAnil Ravindranath rc = TASK_TAG_QUEUE_HEAD; 318589a36810SAnil Ravindranath break; 318689a36810SAnil Ravindranath case MSG_ORDERED_TAG: 318789a36810SAnil Ravindranath rc = TASK_TAG_ORDERED; 318889a36810SAnil Ravindranath break; 318989a36810SAnil Ravindranath }; 319089a36810SAnil Ravindranath } 319189a36810SAnil Ravindranath 319289a36810SAnil Ravindranath return rc; 319389a36810SAnil Ravindranath } 319489a36810SAnil Ravindranath 319589a36810SAnil Ravindranath 319689a36810SAnil Ravindranath /** 319789a36810SAnil Ravindranath * pmcraid_init_ioadls - initializes IOADL related fields in IOARCB 319889a36810SAnil Ravindranath * @cmd: pmcraid command struct 319989a36810SAnil Ravindranath * @sgcount: count of scatter-gather elements 320089a36810SAnil Ravindranath * 320189a36810SAnil Ravindranath * Return value 320289a36810SAnil Ravindranath * returns pointer pmcraid_ioadl_desc, initialized to point to internal 320389a36810SAnil Ravindranath * or external IOADLs 320489a36810SAnil Ravindranath */ 320589a36810SAnil Ravindranath struct pmcraid_ioadl_desc * 320689a36810SAnil Ravindranath pmcraid_init_ioadls(struct pmcraid_cmd *cmd, int sgcount) 320789a36810SAnil Ravindranath { 320889a36810SAnil Ravindranath struct pmcraid_ioadl_desc *ioadl; 320989a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 321089a36810SAnil Ravindranath int ioadl_count = 0; 321189a36810SAnil Ravindranath 321289a36810SAnil Ravindranath if (ioarcb->add_cmd_param_length) 321389a36810SAnil Ravindranath ioadl_count = DIV_ROUND_UP(ioarcb->add_cmd_param_length, 16); 321489a36810SAnil Ravindranath ioarcb->ioadl_length = 321589a36810SAnil Ravindranath sizeof(struct pmcraid_ioadl_desc) * sgcount; 321689a36810SAnil Ravindranath 321789a36810SAnil Ravindranath if ((sgcount + ioadl_count) > (ARRAY_SIZE(ioarcb->add_data.u.ioadl))) { 321889a36810SAnil Ravindranath /* external ioadls start at offset 0x80 from control_block 321989a36810SAnil Ravindranath * structure, re-using 24 out of 27 ioadls part of IOARCB. 322089a36810SAnil Ravindranath * It is necessary to indicate to firmware that driver is 322189a36810SAnil Ravindranath * using ioadls to be treated as external to IOARCB. 322289a36810SAnil Ravindranath */ 322389a36810SAnil Ravindranath ioarcb->ioarcb_bus_addr &= ~(0x1FULL); 322489a36810SAnil Ravindranath ioarcb->ioadl_bus_addr = 322589a36810SAnil Ravindranath cpu_to_le64((cmd->ioa_cb_bus_addr) + 322689a36810SAnil Ravindranath offsetof(struct pmcraid_ioarcb, 322789a36810SAnil Ravindranath add_data.u.ioadl[3])); 322889a36810SAnil Ravindranath ioadl = &ioarcb->add_data.u.ioadl[3]; 322989a36810SAnil Ravindranath } else { 323089a36810SAnil Ravindranath ioarcb->ioadl_bus_addr = 323189a36810SAnil Ravindranath cpu_to_le64((cmd->ioa_cb_bus_addr) + 323289a36810SAnil Ravindranath offsetof(struct pmcraid_ioarcb, 323389a36810SAnil Ravindranath add_data.u.ioadl[ioadl_count])); 323489a36810SAnil Ravindranath 323589a36810SAnil Ravindranath ioadl = &ioarcb->add_data.u.ioadl[ioadl_count]; 323689a36810SAnil Ravindranath ioarcb->ioarcb_bus_addr |= 323789a36810SAnil Ravindranath DIV_ROUND_CLOSEST(sgcount + ioadl_count, 8); 323889a36810SAnil Ravindranath } 323989a36810SAnil Ravindranath 324089a36810SAnil Ravindranath return ioadl; 324189a36810SAnil Ravindranath } 324289a36810SAnil Ravindranath 324389a36810SAnil Ravindranath /** 324489a36810SAnil Ravindranath * pmcraid_build_ioadl - Build a scatter/gather list and map the buffer 324589a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 324689a36810SAnil Ravindranath * @cmd: pmcraid command struct 324789a36810SAnil Ravindranath * 324889a36810SAnil Ravindranath * This function is invoked by queuecommand entry point while sending a command 324989a36810SAnil Ravindranath * to firmware. This builds ioadl descriptors and sets up ioarcb fields. 325089a36810SAnil Ravindranath * 325189a36810SAnil Ravindranath * Return value: 325289a36810SAnil Ravindranath * 0 on success or -1 on failure 325389a36810SAnil Ravindranath */ 325489a36810SAnil Ravindranath static int pmcraid_build_ioadl( 325589a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 325689a36810SAnil Ravindranath struct pmcraid_cmd *cmd 325789a36810SAnil Ravindranath ) 325889a36810SAnil Ravindranath { 325989a36810SAnil Ravindranath int i, nseg; 326089a36810SAnil Ravindranath struct scatterlist *sglist; 326189a36810SAnil Ravindranath 326289a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; 326389a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &(cmd->ioa_cb->ioarcb); 326489a36810SAnil Ravindranath struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; 326589a36810SAnil Ravindranath 326689a36810SAnil Ravindranath u32 length = scsi_bufflen(scsi_cmd); 326789a36810SAnil Ravindranath 326889a36810SAnil Ravindranath if (!length) 326989a36810SAnil Ravindranath return 0; 327089a36810SAnil Ravindranath 327189a36810SAnil Ravindranath nseg = scsi_dma_map(scsi_cmd); 327289a36810SAnil Ravindranath 327389a36810SAnil Ravindranath if (nseg < 0) { 327434876402SAnil Ravindranath scmd_printk(KERN_ERR, scsi_cmd, "scsi_map_dma failed!\n"); 327589a36810SAnil Ravindranath return -1; 327689a36810SAnil Ravindranath } else if (nseg > PMCRAID_MAX_IOADLS) { 327789a36810SAnil Ravindranath scsi_dma_unmap(scsi_cmd); 327834876402SAnil Ravindranath scmd_printk(KERN_ERR, scsi_cmd, 327989a36810SAnil Ravindranath "sg count is (%d) more than allowed!\n", nseg); 328089a36810SAnil Ravindranath return -1; 328189a36810SAnil Ravindranath } 328289a36810SAnil Ravindranath 328389a36810SAnil Ravindranath /* Initialize IOARCB data transfer length fields */ 328489a36810SAnil Ravindranath if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) 328589a36810SAnil Ravindranath ioarcb->request_flags0 |= TRANSFER_DIR_WRITE; 328689a36810SAnil Ravindranath 328789a36810SAnil Ravindranath ioarcb->request_flags0 |= NO_LINK_DESCS; 328889a36810SAnil Ravindranath ioarcb->data_transfer_length = cpu_to_le32(length); 328989a36810SAnil Ravindranath ioadl = pmcraid_init_ioadls(cmd, nseg); 329089a36810SAnil Ravindranath 329189a36810SAnil Ravindranath /* Initialize IOADL descriptor addresses */ 329289a36810SAnil Ravindranath scsi_for_each_sg(scsi_cmd, sglist, nseg, i) { 329389a36810SAnil Ravindranath ioadl[i].data_len = cpu_to_le32(sg_dma_len(sglist)); 329489a36810SAnil Ravindranath ioadl[i].address = cpu_to_le64(sg_dma_address(sglist)); 329589a36810SAnil Ravindranath ioadl[i].flags = 0; 329689a36810SAnil Ravindranath } 329789a36810SAnil Ravindranath /* setup last descriptor */ 329888197966SAnil Ravindranath ioadl[i - 1].flags = IOADL_FLAGS_LAST_DESC; 329989a36810SAnil Ravindranath 330089a36810SAnil Ravindranath return 0; 330189a36810SAnil Ravindranath } 330289a36810SAnil Ravindranath 330389a36810SAnil Ravindranath /** 330489a36810SAnil Ravindranath * pmcraid_free_sglist - Frees an allocated SG buffer list 330589a36810SAnil Ravindranath * @sglist: scatter/gather list pointer 330689a36810SAnil Ravindranath * 330789a36810SAnil Ravindranath * Free a DMA'able memory previously allocated with pmcraid_alloc_sglist 330889a36810SAnil Ravindranath * 330989a36810SAnil Ravindranath * Return value: 331089a36810SAnil Ravindranath * none 331189a36810SAnil Ravindranath */ 331289a36810SAnil Ravindranath static void pmcraid_free_sglist(struct pmcraid_sglist *sglist) 331389a36810SAnil Ravindranath { 331489a36810SAnil Ravindranath int i; 331589a36810SAnil Ravindranath 331689a36810SAnil Ravindranath for (i = 0; i < sglist->num_sg; i++) 331789a36810SAnil Ravindranath __free_pages(sg_page(&(sglist->scatterlist[i])), 331889a36810SAnil Ravindranath sglist->order); 331989a36810SAnil Ravindranath 332089a36810SAnil Ravindranath kfree(sglist); 332189a36810SAnil Ravindranath } 332289a36810SAnil Ravindranath 332389a36810SAnil Ravindranath /** 332489a36810SAnil Ravindranath * pmcraid_alloc_sglist - Allocates memory for a SG list 332589a36810SAnil Ravindranath * @buflen: buffer length 332689a36810SAnil Ravindranath * 332789a36810SAnil Ravindranath * Allocates a DMA'able buffer in chunks and assembles a scatter/gather 332889a36810SAnil Ravindranath * list. 332989a36810SAnil Ravindranath * 333089a36810SAnil Ravindranath * Return value 333189a36810SAnil Ravindranath * pointer to sglist / NULL on failure 333289a36810SAnil Ravindranath */ 333389a36810SAnil Ravindranath static struct pmcraid_sglist *pmcraid_alloc_sglist(int buflen) 333489a36810SAnil Ravindranath { 333589a36810SAnil Ravindranath struct pmcraid_sglist *sglist; 333689a36810SAnil Ravindranath struct scatterlist *scatterlist; 333789a36810SAnil Ravindranath struct page *page; 333889a36810SAnil Ravindranath int num_elem, i, j; 333989a36810SAnil Ravindranath int sg_size; 334089a36810SAnil Ravindranath int order; 334189a36810SAnil Ravindranath int bsize_elem; 334289a36810SAnil Ravindranath 334389a36810SAnil Ravindranath sg_size = buflen / (PMCRAID_MAX_IOADLS - 1); 334489a36810SAnil Ravindranath order = (sg_size > 0) ? get_order(sg_size) : 0; 334589a36810SAnil Ravindranath bsize_elem = PAGE_SIZE * (1 << order); 334689a36810SAnil Ravindranath 334789a36810SAnil Ravindranath /* Determine the actual number of sg entries needed */ 334889a36810SAnil Ravindranath if (buflen % bsize_elem) 334989a36810SAnil Ravindranath num_elem = (buflen / bsize_elem) + 1; 335089a36810SAnil Ravindranath else 335189a36810SAnil Ravindranath num_elem = buflen / bsize_elem; 335289a36810SAnil Ravindranath 335389a36810SAnil Ravindranath /* Allocate a scatter/gather list for the DMA */ 335489a36810SAnil Ravindranath sglist = kzalloc(sizeof(struct pmcraid_sglist) + 335589a36810SAnil Ravindranath (sizeof(struct scatterlist) * (num_elem - 1)), 335689a36810SAnil Ravindranath GFP_KERNEL); 335789a36810SAnil Ravindranath 335889a36810SAnil Ravindranath if (sglist == NULL) 335989a36810SAnil Ravindranath return NULL; 336089a36810SAnil Ravindranath 336189a36810SAnil Ravindranath scatterlist = sglist->scatterlist; 336289a36810SAnil Ravindranath sg_init_table(scatterlist, num_elem); 336389a36810SAnil Ravindranath sglist->order = order; 336489a36810SAnil Ravindranath sglist->num_sg = num_elem; 336589a36810SAnil Ravindranath sg_size = buflen; 336689a36810SAnil Ravindranath 336789a36810SAnil Ravindranath for (i = 0; i < num_elem; i++) { 3368592488a3SAnil Ravindranath page = alloc_pages(GFP_KERNEL|GFP_DMA|__GFP_ZERO, order); 336989a36810SAnil Ravindranath if (!page) { 337089a36810SAnil Ravindranath for (j = i - 1; j >= 0; j--) 337189a36810SAnil Ravindranath __free_pages(sg_page(&scatterlist[j]), order); 337289a36810SAnil Ravindranath kfree(sglist); 337389a36810SAnil Ravindranath return NULL; 337489a36810SAnil Ravindranath } 337589a36810SAnil Ravindranath 337689a36810SAnil Ravindranath sg_set_page(&scatterlist[i], page, 337789a36810SAnil Ravindranath sg_size < bsize_elem ? sg_size : bsize_elem, 0); 337889a36810SAnil Ravindranath sg_size -= bsize_elem; 337989a36810SAnil Ravindranath } 338089a36810SAnil Ravindranath 338189a36810SAnil Ravindranath return sglist; 338289a36810SAnil Ravindranath } 338389a36810SAnil Ravindranath 338489a36810SAnil Ravindranath /** 338589a36810SAnil Ravindranath * pmcraid_copy_sglist - Copy user buffer to kernel buffer's SG list 338689a36810SAnil Ravindranath * @sglist: scatter/gather list pointer 338789a36810SAnil Ravindranath * @buffer: buffer pointer 338889a36810SAnil Ravindranath * @len: buffer length 338989a36810SAnil Ravindranath * @direction: data transfer direction 339089a36810SAnil Ravindranath * 339189a36810SAnil Ravindranath * Copy a user buffer into a buffer allocated by pmcraid_alloc_sglist 339289a36810SAnil Ravindranath * 339389a36810SAnil Ravindranath * Return value: 339489a36810SAnil Ravindranath * 0 on success / other on failure 339589a36810SAnil Ravindranath */ 339689a36810SAnil Ravindranath static int pmcraid_copy_sglist( 339789a36810SAnil Ravindranath struct pmcraid_sglist *sglist, 339889a36810SAnil Ravindranath unsigned long buffer, 339989a36810SAnil Ravindranath u32 len, 340089a36810SAnil Ravindranath int direction 340189a36810SAnil Ravindranath ) 340289a36810SAnil Ravindranath { 340389a36810SAnil Ravindranath struct scatterlist *scatterlist; 340489a36810SAnil Ravindranath void *kaddr; 340589a36810SAnil Ravindranath int bsize_elem; 340689a36810SAnil Ravindranath int i; 340789a36810SAnil Ravindranath int rc = 0; 340889a36810SAnil Ravindranath 340989a36810SAnil Ravindranath /* Determine the actual number of bytes per element */ 341089a36810SAnil Ravindranath bsize_elem = PAGE_SIZE * (1 << sglist->order); 341189a36810SAnil Ravindranath 341289a36810SAnil Ravindranath scatterlist = sglist->scatterlist; 341389a36810SAnil Ravindranath 341489a36810SAnil Ravindranath for (i = 0; i < (len / bsize_elem); i++, buffer += bsize_elem) { 341589a36810SAnil Ravindranath struct page *page = sg_page(&scatterlist[i]); 341689a36810SAnil Ravindranath 341789a36810SAnil Ravindranath kaddr = kmap(page); 341889a36810SAnil Ravindranath if (direction == DMA_TO_DEVICE) 341989a36810SAnil Ravindranath rc = __copy_from_user(kaddr, 342089a36810SAnil Ravindranath (void *)buffer, 342189a36810SAnil Ravindranath bsize_elem); 342289a36810SAnil Ravindranath else 342389a36810SAnil Ravindranath rc = __copy_to_user((void *)buffer, kaddr, bsize_elem); 342489a36810SAnil Ravindranath 342589a36810SAnil Ravindranath kunmap(page); 342689a36810SAnil Ravindranath 342789a36810SAnil Ravindranath if (rc) { 342889a36810SAnil Ravindranath pmcraid_err("failed to copy user data into sg list\n"); 342989a36810SAnil Ravindranath return -EFAULT; 343089a36810SAnil Ravindranath } 343189a36810SAnil Ravindranath 343289a36810SAnil Ravindranath scatterlist[i].length = bsize_elem; 343389a36810SAnil Ravindranath } 343489a36810SAnil Ravindranath 343589a36810SAnil Ravindranath if (len % bsize_elem) { 343689a36810SAnil Ravindranath struct page *page = sg_page(&scatterlist[i]); 343789a36810SAnil Ravindranath 343889a36810SAnil Ravindranath kaddr = kmap(page); 343989a36810SAnil Ravindranath 344089a36810SAnil Ravindranath if (direction == DMA_TO_DEVICE) 344189a36810SAnil Ravindranath rc = __copy_from_user(kaddr, 344289a36810SAnil Ravindranath (void *)buffer, 344389a36810SAnil Ravindranath len % bsize_elem); 344489a36810SAnil Ravindranath else 344589a36810SAnil Ravindranath rc = __copy_to_user((void *)buffer, 344689a36810SAnil Ravindranath kaddr, 344789a36810SAnil Ravindranath len % bsize_elem); 344889a36810SAnil Ravindranath 344989a36810SAnil Ravindranath kunmap(page); 345089a36810SAnil Ravindranath 345189a36810SAnil Ravindranath scatterlist[i].length = len % bsize_elem; 345289a36810SAnil Ravindranath } 345389a36810SAnil Ravindranath 345489a36810SAnil Ravindranath if (rc) { 345589a36810SAnil Ravindranath pmcraid_err("failed to copy user data into sg list\n"); 345689a36810SAnil Ravindranath rc = -EFAULT; 345789a36810SAnil Ravindranath } 345889a36810SAnil Ravindranath 345989a36810SAnil Ravindranath return rc; 346089a36810SAnil Ravindranath } 346189a36810SAnil Ravindranath 346289a36810SAnil Ravindranath /** 346389a36810SAnil Ravindranath * pmcraid_queuecommand - Queue a mid-layer request 346489a36810SAnil Ravindranath * @scsi_cmd: scsi command struct 346589a36810SAnil Ravindranath * @done: done function 346689a36810SAnil Ravindranath * 346789a36810SAnil Ravindranath * This function queues a request generated by the mid-layer. Midlayer calls 346889a36810SAnil Ravindranath * this routine within host->lock. Some of the functions called by queuecommand 346989a36810SAnil Ravindranath * would use cmd block queue locks (free_pool_lock and pending_pool_lock) 347089a36810SAnil Ravindranath * 347189a36810SAnil Ravindranath * Return value: 347289a36810SAnil Ravindranath * 0 on success 347389a36810SAnil Ravindranath * SCSI_MLQUEUE_DEVICE_BUSY if device is busy 347489a36810SAnil Ravindranath * SCSI_MLQUEUE_HOST_BUSY if host is busy 347589a36810SAnil Ravindranath */ 3476f281233dSJeff Garzik static int pmcraid_queuecommand_lck( 347789a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd, 347889a36810SAnil Ravindranath void (*done) (struct scsi_cmnd *) 347989a36810SAnil Ravindranath ) 348089a36810SAnil Ravindranath { 348189a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 348289a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 348389a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb; 348489a36810SAnil Ravindranath struct pmcraid_cmd *cmd; 3485c20c4267SAnil Ravindranath u32 fw_version; 348689a36810SAnil Ravindranath int rc = 0; 348789a36810SAnil Ravindranath 348889a36810SAnil Ravindranath pinstance = 348989a36810SAnil Ravindranath (struct pmcraid_instance *)scsi_cmd->device->host->hostdata; 3490c20c4267SAnil Ravindranath fw_version = be16_to_cpu(pinstance->inq_data->fw_version); 349189a36810SAnil Ravindranath scsi_cmd->scsi_done = done; 349289a36810SAnil Ravindranath res = scsi_cmd->device->hostdata; 349389a36810SAnil Ravindranath scsi_cmd->result = (DID_OK << 16); 349489a36810SAnil Ravindranath 349589a36810SAnil Ravindranath /* if adapter is marked as dead, set result to DID_NO_CONNECT complete 349689a36810SAnil Ravindranath * the command 349789a36810SAnil Ravindranath */ 349889a36810SAnil Ravindranath if (pinstance->ioa_state == IOA_STATE_DEAD) { 349989a36810SAnil Ravindranath pmcraid_info("IOA is dead, but queuecommand is scheduled\n"); 350089a36810SAnil Ravindranath scsi_cmd->result = (DID_NO_CONNECT << 16); 350189a36810SAnil Ravindranath scsi_cmd->scsi_done(scsi_cmd); 350289a36810SAnil Ravindranath return 0; 350389a36810SAnil Ravindranath } 350489a36810SAnil Ravindranath 350589a36810SAnil Ravindranath /* If IOA reset is in progress, can't queue the commands */ 350689a36810SAnil Ravindranath if (pinstance->ioa_reset_in_progress) 350789a36810SAnil Ravindranath return SCSI_MLQUEUE_HOST_BUSY; 350889a36810SAnil Ravindranath 3509c20c4267SAnil Ravindranath /* Firmware doesn't support SYNCHRONIZE_CACHE command (0x35), complete 3510c20c4267SAnil Ravindranath * the command here itself with success return 3511c20c4267SAnil Ravindranath */ 3512c20c4267SAnil Ravindranath if (scsi_cmd->cmnd[0] == SYNCHRONIZE_CACHE) { 3513c20c4267SAnil Ravindranath pmcraid_info("SYNC_CACHE(0x35), completing in driver itself\n"); 3514c20c4267SAnil Ravindranath scsi_cmd->scsi_done(scsi_cmd); 3515c20c4267SAnil Ravindranath return 0; 3516c20c4267SAnil Ravindranath } 3517c20c4267SAnil Ravindranath 351889a36810SAnil Ravindranath /* initialize the command and IOARCB to be sent to IOA */ 351989a36810SAnil Ravindranath cmd = pmcraid_get_free_cmd(pinstance); 352089a36810SAnil Ravindranath 352189a36810SAnil Ravindranath if (cmd == NULL) { 352289a36810SAnil Ravindranath pmcraid_err("free command block is not available\n"); 352389a36810SAnil Ravindranath return SCSI_MLQUEUE_HOST_BUSY; 352489a36810SAnil Ravindranath } 352589a36810SAnil Ravindranath 352689a36810SAnil Ravindranath cmd->scsi_cmd = scsi_cmd; 352789a36810SAnil Ravindranath ioarcb = &(cmd->ioa_cb->ioarcb); 352889a36810SAnil Ravindranath memcpy(ioarcb->cdb, scsi_cmd->cmnd, scsi_cmd->cmd_len); 352989a36810SAnil Ravindranath ioarcb->resource_handle = res->cfg_entry.resource_handle; 353089a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_SCSI; 353189a36810SAnil Ravindranath 3532c20c4267SAnil Ravindranath /* set hrrq number where the IOA should respond to. Note that all cmds 3533c20c4267SAnil Ravindranath * generated internally uses hrrq_id 0, exception to this is the cmd 3534c20c4267SAnil Ravindranath * block of scsi_cmd which is re-used (e.g. cancel/abort), which uses 3535c20c4267SAnil Ravindranath * hrrq_id assigned here in queuecommand 3536c20c4267SAnil Ravindranath */ 3537c20c4267SAnil Ravindranath ioarcb->hrrq_id = atomic_add_return(1, &(pinstance->last_message_id)) % 3538c20c4267SAnil Ravindranath pinstance->num_hrrq; 353989a36810SAnil Ravindranath cmd->cmd_done = pmcraid_io_done; 354089a36810SAnil Ravindranath 354189a36810SAnil Ravindranath if (RES_IS_GSCSI(res->cfg_entry) || RES_IS_VSET(res->cfg_entry)) { 354289a36810SAnil Ravindranath if (scsi_cmd->underflow == 0) 354389a36810SAnil Ravindranath ioarcb->request_flags0 |= INHIBIT_UL_CHECK; 354489a36810SAnil Ravindranath 354589a36810SAnil Ravindranath if (res->sync_reqd) { 354689a36810SAnil Ravindranath ioarcb->request_flags0 |= SYNC_COMPLETE; 354789a36810SAnil Ravindranath res->sync_reqd = 0; 354889a36810SAnil Ravindranath } 354989a36810SAnil Ravindranath 355089a36810SAnil Ravindranath ioarcb->request_flags0 |= NO_LINK_DESCS; 355189a36810SAnil Ravindranath ioarcb->request_flags1 |= pmcraid_task_attributes(scsi_cmd); 355289a36810SAnil Ravindranath 355389a36810SAnil Ravindranath if (RES_IS_GSCSI(res->cfg_entry)) 355489a36810SAnil Ravindranath ioarcb->request_flags1 |= DELAY_AFTER_RESET; 355589a36810SAnil Ravindranath } 355689a36810SAnil Ravindranath 355789a36810SAnil Ravindranath rc = pmcraid_build_ioadl(pinstance, cmd); 355889a36810SAnil Ravindranath 355989a36810SAnil Ravindranath pmcraid_info("command (%d) CDB[0] = %x for %x:%x:%x:%x\n", 356089a36810SAnil Ravindranath le32_to_cpu(ioarcb->response_handle) >> 2, 356189a36810SAnil Ravindranath scsi_cmd->cmnd[0], pinstance->host->unique_id, 356289a36810SAnil Ravindranath RES_IS_VSET(res->cfg_entry) ? PMCRAID_VSET_BUS_ID : 356389a36810SAnil Ravindranath PMCRAID_PHYS_BUS_ID, 356489a36810SAnil Ravindranath RES_IS_VSET(res->cfg_entry) ? 3565c20c4267SAnil Ravindranath (fw_version <= PMCRAID_FW_VERSION_1 ? 356689a36810SAnil Ravindranath res->cfg_entry.unique_flags1 : 3567c20c4267SAnil Ravindranath res->cfg_entry.array_id & 0xFF) : 356889a36810SAnil Ravindranath RES_TARGET(res->cfg_entry.resource_address), 356989a36810SAnil Ravindranath RES_LUN(res->cfg_entry.resource_address)); 357089a36810SAnil Ravindranath 357189a36810SAnil Ravindranath if (likely(rc == 0)) { 357289a36810SAnil Ravindranath _pmcraid_fire_command(cmd); 357389a36810SAnil Ravindranath } else { 357489a36810SAnil Ravindranath pmcraid_err("queuecommand could not build ioadl\n"); 357589a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 357689a36810SAnil Ravindranath rc = SCSI_MLQUEUE_HOST_BUSY; 357789a36810SAnil Ravindranath } 357889a36810SAnil Ravindranath 357989a36810SAnil Ravindranath return rc; 358089a36810SAnil Ravindranath } 358189a36810SAnil Ravindranath 3582f281233dSJeff Garzik static DEF_SCSI_QCMD(pmcraid_queuecommand) 3583f281233dSJeff Garzik 358489a36810SAnil Ravindranath /** 358589a36810SAnil Ravindranath * pmcraid_open -char node "open" entry, allowed only users with admin access 358689a36810SAnil Ravindranath */ 358789a36810SAnil Ravindranath static int pmcraid_chr_open(struct inode *inode, struct file *filep) 358889a36810SAnil Ravindranath { 358989a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 359089a36810SAnil Ravindranath 359189a36810SAnil Ravindranath if (!capable(CAP_SYS_ADMIN)) 359289a36810SAnil Ravindranath return -EACCES; 359389a36810SAnil Ravindranath 359489a36810SAnil Ravindranath /* Populate adapter instance * pointer for use by ioctl */ 359589a36810SAnil Ravindranath pinstance = container_of(inode->i_cdev, struct pmcraid_instance, cdev); 359689a36810SAnil Ravindranath filep->private_data = pinstance; 359789a36810SAnil Ravindranath 359889a36810SAnil Ravindranath return 0; 359989a36810SAnil Ravindranath } 360089a36810SAnil Ravindranath 360189a36810SAnil Ravindranath /** 360289a36810SAnil Ravindranath * pmcraid_release - char node "release" entry point 360389a36810SAnil Ravindranath */ 360489a36810SAnil Ravindranath static int pmcraid_chr_release(struct inode *inode, struct file *filep) 360589a36810SAnil Ravindranath { 3606660bdddbSCyril Jayaprakash struct pmcraid_instance *pinstance = filep->private_data; 360789a36810SAnil Ravindranath 360889a36810SAnil Ravindranath filep->private_data = NULL; 360989a36810SAnil Ravindranath fasync_helper(-1, filep, 0, &pinstance->aen_queue); 361089a36810SAnil Ravindranath 361189a36810SAnil Ravindranath return 0; 361289a36810SAnil Ravindranath } 361389a36810SAnil Ravindranath 361489a36810SAnil Ravindranath /** 361589a36810SAnil Ravindranath * pmcraid_fasync - Async notifier registration from applications 361689a36810SAnil Ravindranath * 361789a36810SAnil Ravindranath * This function adds the calling process to a driver global queue. When an 361889a36810SAnil Ravindranath * event occurs, SIGIO will be sent to all processes in this queue. 361989a36810SAnil Ravindranath */ 362089a36810SAnil Ravindranath static int pmcraid_chr_fasync(int fd, struct file *filep, int mode) 362189a36810SAnil Ravindranath { 362289a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 362389a36810SAnil Ravindranath int rc; 362489a36810SAnil Ravindranath 3625660bdddbSCyril Jayaprakash pinstance = filep->private_data; 362689a36810SAnil Ravindranath mutex_lock(&pinstance->aen_queue_lock); 362789a36810SAnil Ravindranath rc = fasync_helper(fd, filep, mode, &pinstance->aen_queue); 362889a36810SAnil Ravindranath mutex_unlock(&pinstance->aen_queue_lock); 362989a36810SAnil Ravindranath 363089a36810SAnil Ravindranath return rc; 363189a36810SAnil Ravindranath } 363289a36810SAnil Ravindranath 363389a36810SAnil Ravindranath 363489a36810SAnil Ravindranath /** 363589a36810SAnil Ravindranath * pmcraid_build_passthrough_ioadls - builds SG elements for passthrough 363689a36810SAnil Ravindranath * commands sent over IOCTL interface 363789a36810SAnil Ravindranath * 363889a36810SAnil Ravindranath * @cmd : pointer to struct pmcraid_cmd 363989a36810SAnil Ravindranath * @buflen : length of the request buffer 364089a36810SAnil Ravindranath * @direction : data transfer direction 364189a36810SAnil Ravindranath * 364289a36810SAnil Ravindranath * Return value 3643af901ca1SAndré Goddard Rosa * 0 on success, non-zero error code on failure 364489a36810SAnil Ravindranath */ 364589a36810SAnil Ravindranath static int pmcraid_build_passthrough_ioadls( 364689a36810SAnil Ravindranath struct pmcraid_cmd *cmd, 364789a36810SAnil Ravindranath int buflen, 364889a36810SAnil Ravindranath int direction 364989a36810SAnil Ravindranath ) 365089a36810SAnil Ravindranath { 365189a36810SAnil Ravindranath struct pmcraid_sglist *sglist = NULL; 365289a36810SAnil Ravindranath struct scatterlist *sg = NULL; 365389a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 365489a36810SAnil Ravindranath struct pmcraid_ioadl_desc *ioadl; 365589a36810SAnil Ravindranath int i; 365689a36810SAnil Ravindranath 365789a36810SAnil Ravindranath sglist = pmcraid_alloc_sglist(buflen); 365889a36810SAnil Ravindranath 365989a36810SAnil Ravindranath if (!sglist) { 366089a36810SAnil Ravindranath pmcraid_err("can't allocate memory for passthrough SGls\n"); 366189a36810SAnil Ravindranath return -ENOMEM; 366289a36810SAnil Ravindranath } 366389a36810SAnil Ravindranath 366489a36810SAnil Ravindranath sglist->num_dma_sg = pci_map_sg(cmd->drv_inst->pdev, 366589a36810SAnil Ravindranath sglist->scatterlist, 366689a36810SAnil Ravindranath sglist->num_sg, direction); 366789a36810SAnil Ravindranath 366889a36810SAnil Ravindranath if (!sglist->num_dma_sg || sglist->num_dma_sg > PMCRAID_MAX_IOADLS) { 366989a36810SAnil Ravindranath dev_err(&cmd->drv_inst->pdev->dev, 367089a36810SAnil Ravindranath "Failed to map passthrough buffer!\n"); 367189a36810SAnil Ravindranath pmcraid_free_sglist(sglist); 367289a36810SAnil Ravindranath return -EIO; 367389a36810SAnil Ravindranath } 367489a36810SAnil Ravindranath 367589a36810SAnil Ravindranath cmd->sglist = sglist; 367689a36810SAnil Ravindranath ioarcb->request_flags0 |= NO_LINK_DESCS; 367789a36810SAnil Ravindranath 367889a36810SAnil Ravindranath ioadl = pmcraid_init_ioadls(cmd, sglist->num_dma_sg); 367989a36810SAnil Ravindranath 368089a36810SAnil Ravindranath /* Initialize IOADL descriptor addresses */ 368189a36810SAnil Ravindranath for_each_sg(sglist->scatterlist, sg, sglist->num_dma_sg, i) { 368289a36810SAnil Ravindranath ioadl[i].data_len = cpu_to_le32(sg_dma_len(sg)); 368389a36810SAnil Ravindranath ioadl[i].address = cpu_to_le64(sg_dma_address(sg)); 368489a36810SAnil Ravindranath ioadl[i].flags = 0; 368589a36810SAnil Ravindranath } 368689a36810SAnil Ravindranath 368789a36810SAnil Ravindranath /* setup the last descriptor */ 368888197966SAnil Ravindranath ioadl[i - 1].flags = IOADL_FLAGS_LAST_DESC; 368989a36810SAnil Ravindranath 369089a36810SAnil Ravindranath return 0; 369189a36810SAnil Ravindranath } 369289a36810SAnil Ravindranath 369389a36810SAnil Ravindranath 369489a36810SAnil Ravindranath /** 369589a36810SAnil Ravindranath * pmcraid_release_passthrough_ioadls - release passthrough ioadls 369689a36810SAnil Ravindranath * 369789a36810SAnil Ravindranath * @cmd: pointer to struct pmcraid_cmd for which ioadls were allocated 369889a36810SAnil Ravindranath * @buflen: size of the request buffer 369989a36810SAnil Ravindranath * @direction: data transfer direction 370089a36810SAnil Ravindranath * 370189a36810SAnil Ravindranath * Return value 3702af901ca1SAndré Goddard Rosa * 0 on success, non-zero error code on failure 370389a36810SAnil Ravindranath */ 370489a36810SAnil Ravindranath static void pmcraid_release_passthrough_ioadls( 370589a36810SAnil Ravindranath struct pmcraid_cmd *cmd, 370689a36810SAnil Ravindranath int buflen, 370789a36810SAnil Ravindranath int direction 370889a36810SAnil Ravindranath ) 370989a36810SAnil Ravindranath { 371089a36810SAnil Ravindranath struct pmcraid_sglist *sglist = cmd->sglist; 371189a36810SAnil Ravindranath 371289a36810SAnil Ravindranath if (buflen > 0) { 371389a36810SAnil Ravindranath pci_unmap_sg(cmd->drv_inst->pdev, 371489a36810SAnil Ravindranath sglist->scatterlist, 371589a36810SAnil Ravindranath sglist->num_sg, 371689a36810SAnil Ravindranath direction); 371789a36810SAnil Ravindranath pmcraid_free_sglist(sglist); 371889a36810SAnil Ravindranath cmd->sglist = NULL; 371989a36810SAnil Ravindranath } 372089a36810SAnil Ravindranath } 372189a36810SAnil Ravindranath 372289a36810SAnil Ravindranath /** 372389a36810SAnil Ravindranath * pmcraid_ioctl_passthrough - handling passthrough IOCTL commands 372489a36810SAnil Ravindranath * 372589a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 372689a36810SAnil Ravindranath * @cmd: ioctl code 372789a36810SAnil Ravindranath * @arg: pointer to pmcraid_passthrough_buffer user buffer 372889a36810SAnil Ravindranath * 372989a36810SAnil Ravindranath * Return value 3730af901ca1SAndré Goddard Rosa * 0 on success, non-zero error code on failure 373189a36810SAnil Ravindranath */ 373289a36810SAnil Ravindranath static long pmcraid_ioctl_passthrough( 373389a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 373489a36810SAnil Ravindranath unsigned int ioctl_cmd, 373589a36810SAnil Ravindranath unsigned int buflen, 373689a36810SAnil Ravindranath unsigned long arg 373789a36810SAnil Ravindranath ) 373889a36810SAnil Ravindranath { 373989a36810SAnil Ravindranath struct pmcraid_passthrough_ioctl_buffer *buffer; 374089a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb; 374189a36810SAnil Ravindranath struct pmcraid_cmd *cmd; 374289a36810SAnil Ravindranath struct pmcraid_cmd *cancel_cmd; 374389a36810SAnil Ravindranath unsigned long request_buffer; 374489a36810SAnil Ravindranath unsigned long request_offset; 374589a36810SAnil Ravindranath unsigned long lock_flags; 3746592488a3SAnil Ravindranath void *ioasa; 3747c20c4267SAnil Ravindranath u32 ioasc; 374889a36810SAnil Ravindranath int request_size; 374989a36810SAnil Ravindranath int buffer_size; 375089a36810SAnil Ravindranath u8 access, direction; 375189a36810SAnil Ravindranath int rc = 0; 375289a36810SAnil Ravindranath 375389a36810SAnil Ravindranath /* If IOA reset is in progress, wait 10 secs for reset to complete */ 375489a36810SAnil Ravindranath if (pinstance->ioa_reset_in_progress) { 375589a36810SAnil Ravindranath rc = wait_event_interruptible_timeout( 375689a36810SAnil Ravindranath pinstance->reset_wait_q, 375789a36810SAnil Ravindranath !pinstance->ioa_reset_in_progress, 375889a36810SAnil Ravindranath msecs_to_jiffies(10000)); 375989a36810SAnil Ravindranath 376089a36810SAnil Ravindranath if (!rc) 376189a36810SAnil Ravindranath return -ETIMEDOUT; 376289a36810SAnil Ravindranath else if (rc < 0) 376389a36810SAnil Ravindranath return -ERESTARTSYS; 376489a36810SAnil Ravindranath } 376589a36810SAnil Ravindranath 376689a36810SAnil Ravindranath /* If adapter is not in operational state, return error */ 376789a36810SAnil Ravindranath if (pinstance->ioa_state != IOA_STATE_OPERATIONAL) { 376889a36810SAnil Ravindranath pmcraid_err("IOA is not operational\n"); 376989a36810SAnil Ravindranath return -ENOTTY; 377089a36810SAnil Ravindranath } 377189a36810SAnil Ravindranath 377289a36810SAnil Ravindranath buffer_size = sizeof(struct pmcraid_passthrough_ioctl_buffer); 377389a36810SAnil Ravindranath buffer = kmalloc(buffer_size, GFP_KERNEL); 377489a36810SAnil Ravindranath 377589a36810SAnil Ravindranath if (!buffer) { 377689a36810SAnil Ravindranath pmcraid_err("no memory for passthrough buffer\n"); 377789a36810SAnil Ravindranath return -ENOMEM; 377889a36810SAnil Ravindranath } 377989a36810SAnil Ravindranath 378089a36810SAnil Ravindranath request_offset = 378189a36810SAnil Ravindranath offsetof(struct pmcraid_passthrough_ioctl_buffer, request_buffer); 378289a36810SAnil Ravindranath 378389a36810SAnil Ravindranath request_buffer = arg + request_offset; 378489a36810SAnil Ravindranath 378589a36810SAnil Ravindranath rc = __copy_from_user(buffer, 378689a36810SAnil Ravindranath (struct pmcraid_passthrough_ioctl_buffer *) arg, 378789a36810SAnil Ravindranath sizeof(struct pmcraid_passthrough_ioctl_buffer)); 3788592488a3SAnil Ravindranath 3789592488a3SAnil Ravindranath ioasa = 3790592488a3SAnil Ravindranath (void *)(arg + 3791592488a3SAnil Ravindranath offsetof(struct pmcraid_passthrough_ioctl_buffer, ioasa)); 3792592488a3SAnil Ravindranath 379389a36810SAnil Ravindranath if (rc) { 379489a36810SAnil Ravindranath pmcraid_err("ioctl: can't copy passthrough buffer\n"); 379589a36810SAnil Ravindranath rc = -EFAULT; 379689a36810SAnil Ravindranath goto out_free_buffer; 379789a36810SAnil Ravindranath } 379889a36810SAnil Ravindranath 379989a36810SAnil Ravindranath request_size = buffer->ioarcb.data_transfer_length; 380089a36810SAnil Ravindranath 380189a36810SAnil Ravindranath if (buffer->ioarcb.request_flags0 & TRANSFER_DIR_WRITE) { 380289a36810SAnil Ravindranath access = VERIFY_READ; 380389a36810SAnil Ravindranath direction = DMA_TO_DEVICE; 380489a36810SAnil Ravindranath } else { 380589a36810SAnil Ravindranath access = VERIFY_WRITE; 380689a36810SAnil Ravindranath direction = DMA_FROM_DEVICE; 380789a36810SAnil Ravindranath } 380889a36810SAnil Ravindranath 380989a36810SAnil Ravindranath if (request_size > 0) { 381089a36810SAnil Ravindranath rc = access_ok(access, arg, request_offset + request_size); 381189a36810SAnil Ravindranath 381289a36810SAnil Ravindranath if (!rc) { 381389a36810SAnil Ravindranath rc = -EFAULT; 381489a36810SAnil Ravindranath goto out_free_buffer; 381589a36810SAnil Ravindranath } 38165f6279daSDan Rosenberg } else if (request_size < 0) { 38175f6279daSDan Rosenberg rc = -EINVAL; 38185f6279daSDan Rosenberg goto out_free_buffer; 381989a36810SAnil Ravindranath } 382089a36810SAnil Ravindranath 382189a36810SAnil Ravindranath /* check if we have any additional command parameters */ 382289a36810SAnil Ravindranath if (buffer->ioarcb.add_cmd_param_length > PMCRAID_ADD_CMD_PARAM_LEN) { 382389a36810SAnil Ravindranath rc = -EINVAL; 382489a36810SAnil Ravindranath goto out_free_buffer; 382589a36810SAnil Ravindranath } 382689a36810SAnil Ravindranath 382789a36810SAnil Ravindranath cmd = pmcraid_get_free_cmd(pinstance); 382889a36810SAnil Ravindranath 382989a36810SAnil Ravindranath if (!cmd) { 383089a36810SAnil Ravindranath pmcraid_err("free command block is not available\n"); 383189a36810SAnil Ravindranath rc = -ENOMEM; 383289a36810SAnil Ravindranath goto out_free_buffer; 383389a36810SAnil Ravindranath } 383489a36810SAnil Ravindranath 383589a36810SAnil Ravindranath cmd->scsi_cmd = NULL; 383689a36810SAnil Ravindranath ioarcb = &(cmd->ioa_cb->ioarcb); 383789a36810SAnil Ravindranath 383889a36810SAnil Ravindranath /* Copy the user-provided IOARCB stuff field by field */ 383989a36810SAnil Ravindranath ioarcb->resource_handle = buffer->ioarcb.resource_handle; 384089a36810SAnil Ravindranath ioarcb->data_transfer_length = buffer->ioarcb.data_transfer_length; 384189a36810SAnil Ravindranath ioarcb->cmd_timeout = buffer->ioarcb.cmd_timeout; 384289a36810SAnil Ravindranath ioarcb->request_type = buffer->ioarcb.request_type; 384389a36810SAnil Ravindranath ioarcb->request_flags0 = buffer->ioarcb.request_flags0; 384489a36810SAnil Ravindranath ioarcb->request_flags1 = buffer->ioarcb.request_flags1; 384589a36810SAnil Ravindranath memcpy(ioarcb->cdb, buffer->ioarcb.cdb, PMCRAID_MAX_CDB_LEN); 384689a36810SAnil Ravindranath 384789a36810SAnil Ravindranath if (buffer->ioarcb.add_cmd_param_length) { 384889a36810SAnil Ravindranath ioarcb->add_cmd_param_length = 384989a36810SAnil Ravindranath buffer->ioarcb.add_cmd_param_length; 385089a36810SAnil Ravindranath ioarcb->add_cmd_param_offset = 385189a36810SAnil Ravindranath buffer->ioarcb.add_cmd_param_offset; 385289a36810SAnil Ravindranath memcpy(ioarcb->add_data.u.add_cmd_params, 385389a36810SAnil Ravindranath buffer->ioarcb.add_data.u.add_cmd_params, 385489a36810SAnil Ravindranath buffer->ioarcb.add_cmd_param_length); 385589a36810SAnil Ravindranath } 385689a36810SAnil Ravindranath 3857c20c4267SAnil Ravindranath /* set hrrq number where the IOA should respond to. Note that all cmds 3858c20c4267SAnil Ravindranath * generated internally uses hrrq_id 0, exception to this is the cmd 3859c20c4267SAnil Ravindranath * block of scsi_cmd which is re-used (e.g. cancel/abort), which uses 3860c20c4267SAnil Ravindranath * hrrq_id assigned here in queuecommand 3861c20c4267SAnil Ravindranath */ 3862c20c4267SAnil Ravindranath ioarcb->hrrq_id = atomic_add_return(1, &(pinstance->last_message_id)) % 3863c20c4267SAnil Ravindranath pinstance->num_hrrq; 3864c20c4267SAnil Ravindranath 386589a36810SAnil Ravindranath if (request_size) { 386689a36810SAnil Ravindranath rc = pmcraid_build_passthrough_ioadls(cmd, 386789a36810SAnil Ravindranath request_size, 386889a36810SAnil Ravindranath direction); 386989a36810SAnil Ravindranath if (rc) { 387089a36810SAnil Ravindranath pmcraid_err("couldn't build passthrough ioadls\n"); 387189a36810SAnil Ravindranath goto out_free_buffer; 387289a36810SAnil Ravindranath } 3873b5b51544SDan Rosenberg } else if (request_size < 0) { 3874b5b51544SDan Rosenberg rc = -EINVAL; 3875b5b51544SDan Rosenberg goto out_free_buffer; 387689a36810SAnil Ravindranath } 387789a36810SAnil Ravindranath 387889a36810SAnil Ravindranath /* If data is being written into the device, copy the data from user 387989a36810SAnil Ravindranath * buffers 388089a36810SAnil Ravindranath */ 388189a36810SAnil Ravindranath if (direction == DMA_TO_DEVICE && request_size > 0) { 388289a36810SAnil Ravindranath rc = pmcraid_copy_sglist(cmd->sglist, 388389a36810SAnil Ravindranath request_buffer, 388489a36810SAnil Ravindranath request_size, 388589a36810SAnil Ravindranath direction); 388689a36810SAnil Ravindranath if (rc) { 388789a36810SAnil Ravindranath pmcraid_err("failed to copy user buffer\n"); 388889a36810SAnil Ravindranath goto out_free_sglist; 388989a36810SAnil Ravindranath } 389089a36810SAnil Ravindranath } 389189a36810SAnil Ravindranath 389289a36810SAnil Ravindranath /* passthrough ioctl is a blocking command so, put the user to sleep 389389a36810SAnil Ravindranath * until timeout. Note that a timeout value of 0 means, do timeout. 389489a36810SAnil Ravindranath */ 389589a36810SAnil Ravindranath cmd->cmd_done = pmcraid_internal_done; 389689a36810SAnil Ravindranath init_completion(&cmd->wait_for_completion); 389789a36810SAnil Ravindranath cmd->completion_req = 1; 389889a36810SAnil Ravindranath 389989a36810SAnil Ravindranath pmcraid_info("command(%d) (CDB[0] = %x) for %x\n", 390089a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle) >> 2, 390189a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 390289a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioarcb.resource_handle)); 390389a36810SAnil Ravindranath 390489a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 390589a36810SAnil Ravindranath _pmcraid_fire_command(cmd); 390689a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 390789a36810SAnil Ravindranath 3908c20c4267SAnil Ravindranath /* NOTE ! Remove the below line once abort_task is implemented 3909c20c4267SAnil Ravindranath * in firmware. This line disables ioctl command timeout handling logic 3910c20c4267SAnil Ravindranath * similar to IO command timeout handling, making ioctl commands to wait 3911c20c4267SAnil Ravindranath * until the command completion regardless of timeout value specified in 3912c20c4267SAnil Ravindranath * ioarcb 3913c20c4267SAnil Ravindranath */ 3914c20c4267SAnil Ravindranath buffer->ioarcb.cmd_timeout = 0; 3915c20c4267SAnil Ravindranath 391689a36810SAnil Ravindranath /* If command timeout is specified put caller to wait till that time, 391789a36810SAnil Ravindranath * otherwise it would be blocking wait. If command gets timed out, it 391889a36810SAnil Ravindranath * will be aborted. 391989a36810SAnil Ravindranath */ 392089a36810SAnil Ravindranath if (buffer->ioarcb.cmd_timeout == 0) { 392189a36810SAnil Ravindranath wait_for_completion(&cmd->wait_for_completion); 392289a36810SAnil Ravindranath } else if (!wait_for_completion_timeout( 392389a36810SAnil Ravindranath &cmd->wait_for_completion, 392489a36810SAnil Ravindranath msecs_to_jiffies(buffer->ioarcb.cmd_timeout * 1000))) { 392589a36810SAnil Ravindranath 392689a36810SAnil Ravindranath pmcraid_info("aborting cmd %d (CDB[0] = %x) due to timeout\n", 392789a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle >> 2), 392889a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0]); 392989a36810SAnil Ravindranath 393089a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 393189a36810SAnil Ravindranath cancel_cmd = pmcraid_abort_cmd(cmd); 393289a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 393389a36810SAnil Ravindranath 393489a36810SAnil Ravindranath if (cancel_cmd) { 393589a36810SAnil Ravindranath wait_for_completion(&cancel_cmd->wait_for_completion); 3936c20c4267SAnil Ravindranath ioasc = cancel_cmd->ioa_cb->ioasa.ioasc; 393789a36810SAnil Ravindranath pmcraid_return_cmd(cancel_cmd); 3938c20c4267SAnil Ravindranath 3939c20c4267SAnil Ravindranath /* if abort task couldn't find the command i.e it got 3940c20c4267SAnil Ravindranath * completed prior to aborting, return good completion. 394125985edcSLucas De Marchi * if command got aborted successfully or there was IOA 3942c20c4267SAnil Ravindranath * reset due to abort task itself getting timedout then 3943c20c4267SAnil Ravindranath * return -ETIMEDOUT 3944c20c4267SAnil Ravindranath */ 3945c20c4267SAnil Ravindranath if (ioasc == PMCRAID_IOASC_IOA_WAS_RESET || 3946c20c4267SAnil Ravindranath PMCRAID_IOASC_SENSE_KEY(ioasc) == 0x00) { 3947c20c4267SAnil Ravindranath if (ioasc != PMCRAID_IOASC_GC_IOARCB_NOTFOUND) 3948c20c4267SAnil Ravindranath rc = -ETIMEDOUT; 3949c20c4267SAnil Ravindranath goto out_handle_response; 3950c20c4267SAnil Ravindranath } 395189a36810SAnil Ravindranath } 395289a36810SAnil Ravindranath 3953c20c4267SAnil Ravindranath /* no command block for abort task or abort task failed to abort 3954c20c4267SAnil Ravindranath * the IOARCB, then wait for 150 more seconds and initiate reset 3955c20c4267SAnil Ravindranath * sequence after timeout 3956c20c4267SAnil Ravindranath */ 3957c20c4267SAnil Ravindranath if (!wait_for_completion_timeout( 3958c20c4267SAnil Ravindranath &cmd->wait_for_completion, 3959c20c4267SAnil Ravindranath msecs_to_jiffies(150 * 1000))) { 3960c20c4267SAnil Ravindranath pmcraid_reset_bringup(cmd->drv_inst); 3961c20c4267SAnil Ravindranath rc = -ETIMEDOUT; 3962c20c4267SAnil Ravindranath } 396389a36810SAnil Ravindranath } 396489a36810SAnil Ravindranath 3965c20c4267SAnil Ravindranath out_handle_response: 3966592488a3SAnil Ravindranath /* copy entire IOASA buffer and return IOCTL success. 3967592488a3SAnil Ravindranath * If copying IOASA to user-buffer fails, return 396889a36810SAnil Ravindranath * EFAULT 396989a36810SAnil Ravindranath */ 397089a36810SAnil Ravindranath if (copy_to_user(ioasa, &cmd->ioa_cb->ioasa, 397189a36810SAnil Ravindranath sizeof(struct pmcraid_ioasa))) { 397289a36810SAnil Ravindranath pmcraid_err("failed to copy ioasa buffer to user\n"); 397389a36810SAnil Ravindranath rc = -EFAULT; 397489a36810SAnil Ravindranath } 3975c20c4267SAnil Ravindranath 397689a36810SAnil Ravindranath /* If the data transfer was from device, copy the data onto user 397789a36810SAnil Ravindranath * buffers 397889a36810SAnil Ravindranath */ 397989a36810SAnil Ravindranath else if (direction == DMA_FROM_DEVICE && request_size > 0) { 398089a36810SAnil Ravindranath rc = pmcraid_copy_sglist(cmd->sglist, 398189a36810SAnil Ravindranath request_buffer, 398289a36810SAnil Ravindranath request_size, 398389a36810SAnil Ravindranath direction); 398489a36810SAnil Ravindranath if (rc) { 398589a36810SAnil Ravindranath pmcraid_err("failed to copy user buffer\n"); 398689a36810SAnil Ravindranath rc = -EFAULT; 398789a36810SAnil Ravindranath } 398889a36810SAnil Ravindranath } 398989a36810SAnil Ravindranath 399089a36810SAnil Ravindranath out_free_sglist: 399189a36810SAnil Ravindranath pmcraid_release_passthrough_ioadls(cmd, request_size, direction); 399289a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 399389a36810SAnil Ravindranath 399489a36810SAnil Ravindranath out_free_buffer: 399589a36810SAnil Ravindranath kfree(buffer); 399689a36810SAnil Ravindranath 399789a36810SAnil Ravindranath return rc; 399889a36810SAnil Ravindranath } 399989a36810SAnil Ravindranath 400089a36810SAnil Ravindranath 400189a36810SAnil Ravindranath 400289a36810SAnil Ravindranath 400389a36810SAnil Ravindranath /** 400489a36810SAnil Ravindranath * pmcraid_ioctl_driver - ioctl handler for commands handled by driver itself 400589a36810SAnil Ravindranath * 400689a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 400789a36810SAnil Ravindranath * @cmd: ioctl command passed in 400889a36810SAnil Ravindranath * @buflen: length of user_buffer 400989a36810SAnil Ravindranath * @user_buffer: user buffer pointer 401089a36810SAnil Ravindranath * 401189a36810SAnil Ravindranath * Return Value 401289a36810SAnil Ravindranath * 0 in case of success, otherwise appropriate error code 401389a36810SAnil Ravindranath */ 401489a36810SAnil Ravindranath static long pmcraid_ioctl_driver( 401589a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 401689a36810SAnil Ravindranath unsigned int cmd, 401789a36810SAnil Ravindranath unsigned int buflen, 401889a36810SAnil Ravindranath void __user *user_buffer 401989a36810SAnil Ravindranath ) 402089a36810SAnil Ravindranath { 402189a36810SAnil Ravindranath int rc = -ENOSYS; 402289a36810SAnil Ravindranath 402389a36810SAnil Ravindranath if (!access_ok(VERIFY_READ, user_buffer, _IOC_SIZE(cmd))) { 402489a36810SAnil Ravindranath pmcraid_err("ioctl_driver: access fault in request buffer\n"); 402589a36810SAnil Ravindranath return -EFAULT; 402689a36810SAnil Ravindranath } 402789a36810SAnil Ravindranath 402889a36810SAnil Ravindranath switch (cmd) { 402989a36810SAnil Ravindranath case PMCRAID_IOCTL_RESET_ADAPTER: 403089a36810SAnil Ravindranath pmcraid_reset_bringup(pinstance); 403189a36810SAnil Ravindranath rc = 0; 403289a36810SAnil Ravindranath break; 403389a36810SAnil Ravindranath 403489a36810SAnil Ravindranath default: 403589a36810SAnil Ravindranath break; 403689a36810SAnil Ravindranath } 403789a36810SAnil Ravindranath 403889a36810SAnil Ravindranath return rc; 403989a36810SAnil Ravindranath } 404089a36810SAnil Ravindranath 404189a36810SAnil Ravindranath /** 404289a36810SAnil Ravindranath * pmcraid_check_ioctl_buffer - check for proper access to user buffer 404389a36810SAnil Ravindranath * 404489a36810SAnil Ravindranath * @cmd: ioctl command 404589a36810SAnil Ravindranath * @arg: user buffer 404689a36810SAnil Ravindranath * @hdr: pointer to kernel memory for pmcraid_ioctl_header 404789a36810SAnil Ravindranath * 404889a36810SAnil Ravindranath * Return Value 404989a36810SAnil Ravindranath * negetive error code if there are access issues, otherwise zero. 405089a36810SAnil Ravindranath * Upon success, returns ioctl header copied out of user buffer. 405189a36810SAnil Ravindranath */ 405289a36810SAnil Ravindranath 405389a36810SAnil Ravindranath static int pmcraid_check_ioctl_buffer( 405489a36810SAnil Ravindranath int cmd, 405589a36810SAnil Ravindranath void __user *arg, 405689a36810SAnil Ravindranath struct pmcraid_ioctl_header *hdr 405789a36810SAnil Ravindranath ) 405889a36810SAnil Ravindranath { 405989a36810SAnil Ravindranath int rc = 0; 406089a36810SAnil Ravindranath int access = VERIFY_READ; 406189a36810SAnil Ravindranath 406289a36810SAnil Ravindranath if (copy_from_user(hdr, arg, sizeof(struct pmcraid_ioctl_header))) { 406389a36810SAnil Ravindranath pmcraid_err("couldn't copy ioctl header from user buffer\n"); 406489a36810SAnil Ravindranath return -EFAULT; 406589a36810SAnil Ravindranath } 406689a36810SAnil Ravindranath 406789a36810SAnil Ravindranath /* check for valid driver signature */ 406889a36810SAnil Ravindranath rc = memcmp(hdr->signature, 406989a36810SAnil Ravindranath PMCRAID_IOCTL_SIGNATURE, 407089a36810SAnil Ravindranath sizeof(hdr->signature)); 407189a36810SAnil Ravindranath if (rc) { 407289a36810SAnil Ravindranath pmcraid_err("signature verification failed\n"); 407389a36810SAnil Ravindranath return -EINVAL; 407489a36810SAnil Ravindranath } 407589a36810SAnil Ravindranath 407689a36810SAnil Ravindranath /* check for appropriate buffer access */ 407789a36810SAnil Ravindranath if ((_IOC_DIR(cmd) & _IOC_READ) == _IOC_READ) 407889a36810SAnil Ravindranath access = VERIFY_WRITE; 407989a36810SAnil Ravindranath 408089a36810SAnil Ravindranath rc = access_ok(access, 408189a36810SAnil Ravindranath (arg + sizeof(struct pmcraid_ioctl_header)), 408289a36810SAnil Ravindranath hdr->buffer_length); 408389a36810SAnil Ravindranath if (!rc) { 408489a36810SAnil Ravindranath pmcraid_err("access failed for user buffer of size %d\n", 408589a36810SAnil Ravindranath hdr->buffer_length); 408689a36810SAnil Ravindranath return -EFAULT; 408789a36810SAnil Ravindranath } 408889a36810SAnil Ravindranath 408989a36810SAnil Ravindranath return 0; 409089a36810SAnil Ravindranath } 409189a36810SAnil Ravindranath 409289a36810SAnil Ravindranath /** 409389a36810SAnil Ravindranath * pmcraid_ioctl - char node ioctl entry point 409489a36810SAnil Ravindranath */ 409589a36810SAnil Ravindranath static long pmcraid_chr_ioctl( 409689a36810SAnil Ravindranath struct file *filep, 409789a36810SAnil Ravindranath unsigned int cmd, 409889a36810SAnil Ravindranath unsigned long arg 409989a36810SAnil Ravindranath ) 410089a36810SAnil Ravindranath { 410189a36810SAnil Ravindranath struct pmcraid_instance *pinstance = NULL; 410289a36810SAnil Ravindranath struct pmcraid_ioctl_header *hdr = NULL; 410389a36810SAnil Ravindranath int retval = -ENOTTY; 410489a36810SAnil Ravindranath 4105a63ec376SDave Jones hdr = kmalloc(sizeof(struct pmcraid_ioctl_header), GFP_KERNEL); 410689a36810SAnil Ravindranath 410789a36810SAnil Ravindranath if (!hdr) { 41084f91b114SJesper Juhl pmcraid_err("failed to allocate memory for ioctl header\n"); 410989a36810SAnil Ravindranath return -ENOMEM; 411089a36810SAnil Ravindranath } 411189a36810SAnil Ravindranath 411289a36810SAnil Ravindranath retval = pmcraid_check_ioctl_buffer(cmd, (void *)arg, hdr); 411389a36810SAnil Ravindranath 411489a36810SAnil Ravindranath if (retval) { 411589a36810SAnil Ravindranath pmcraid_info("chr_ioctl: header check failed\n"); 411689a36810SAnil Ravindranath kfree(hdr); 411789a36810SAnil Ravindranath return retval; 411889a36810SAnil Ravindranath } 411989a36810SAnil Ravindranath 4120660bdddbSCyril Jayaprakash pinstance = filep->private_data; 412189a36810SAnil Ravindranath 412289a36810SAnil Ravindranath if (!pinstance) { 412389a36810SAnil Ravindranath pmcraid_info("adapter instance is not found\n"); 412489a36810SAnil Ravindranath kfree(hdr); 412589a36810SAnil Ravindranath return -ENOTTY; 412689a36810SAnil Ravindranath } 412789a36810SAnil Ravindranath 412889a36810SAnil Ravindranath switch (_IOC_TYPE(cmd)) { 412989a36810SAnil Ravindranath 413089a36810SAnil Ravindranath case PMCRAID_PASSTHROUGH_IOCTL: 413189a36810SAnil Ravindranath /* If ioctl code is to download microcode, we need to block 413289a36810SAnil Ravindranath * mid-layer requests. 413389a36810SAnil Ravindranath */ 413489a36810SAnil Ravindranath if (cmd == PMCRAID_IOCTL_DOWNLOAD_MICROCODE) 413589a36810SAnil Ravindranath scsi_block_requests(pinstance->host); 413689a36810SAnil Ravindranath 413789a36810SAnil Ravindranath retval = pmcraid_ioctl_passthrough(pinstance, 413889a36810SAnil Ravindranath cmd, 413989a36810SAnil Ravindranath hdr->buffer_length, 414089a36810SAnil Ravindranath arg); 414189a36810SAnil Ravindranath 414289a36810SAnil Ravindranath if (cmd == PMCRAID_IOCTL_DOWNLOAD_MICROCODE) 414389a36810SAnil Ravindranath scsi_unblock_requests(pinstance->host); 414489a36810SAnil Ravindranath break; 414589a36810SAnil Ravindranath 414689a36810SAnil Ravindranath case PMCRAID_DRIVER_IOCTL: 414789a36810SAnil Ravindranath arg += sizeof(struct pmcraid_ioctl_header); 414889a36810SAnil Ravindranath retval = pmcraid_ioctl_driver(pinstance, 414989a36810SAnil Ravindranath cmd, 415089a36810SAnil Ravindranath hdr->buffer_length, 415189a36810SAnil Ravindranath (void __user *)arg); 415289a36810SAnil Ravindranath break; 415389a36810SAnil Ravindranath 415489a36810SAnil Ravindranath default: 415589a36810SAnil Ravindranath retval = -ENOTTY; 415689a36810SAnil Ravindranath break; 415789a36810SAnil Ravindranath } 415889a36810SAnil Ravindranath 415989a36810SAnil Ravindranath kfree(hdr); 416089a36810SAnil Ravindranath 416189a36810SAnil Ravindranath return retval; 416289a36810SAnil Ravindranath } 416389a36810SAnil Ravindranath 416489a36810SAnil Ravindranath /** 416589a36810SAnil Ravindranath * File operations structure for management interface 416689a36810SAnil Ravindranath */ 416789a36810SAnil Ravindranath static const struct file_operations pmcraid_fops = { 416889a36810SAnil Ravindranath .owner = THIS_MODULE, 416989a36810SAnil Ravindranath .open = pmcraid_chr_open, 417089a36810SAnil Ravindranath .release = pmcraid_chr_release, 417189a36810SAnil Ravindranath .fasync = pmcraid_chr_fasync, 417289a36810SAnil Ravindranath .unlocked_ioctl = pmcraid_chr_ioctl, 417389a36810SAnil Ravindranath #ifdef CONFIG_COMPAT 417489a36810SAnil Ravindranath .compat_ioctl = pmcraid_chr_ioctl, 417589a36810SAnil Ravindranath #endif 41766038f373SArnd Bergmann .llseek = noop_llseek, 417789a36810SAnil Ravindranath }; 417889a36810SAnil Ravindranath 417989a36810SAnil Ravindranath 418089a36810SAnil Ravindranath 418189a36810SAnil Ravindranath 418289a36810SAnil Ravindranath /** 418389a36810SAnil Ravindranath * pmcraid_show_log_level - Display adapter's error logging level 418489a36810SAnil Ravindranath * @dev: class device struct 418589a36810SAnil Ravindranath * @buf: buffer 418689a36810SAnil Ravindranath * 418789a36810SAnil Ravindranath * Return value: 418889a36810SAnil Ravindranath * number of bytes printed to buffer 418989a36810SAnil Ravindranath */ 419089a36810SAnil Ravindranath static ssize_t pmcraid_show_log_level( 419189a36810SAnil Ravindranath struct device *dev, 419289a36810SAnil Ravindranath struct device_attribute *attr, 419389a36810SAnil Ravindranath char *buf) 419489a36810SAnil Ravindranath { 419589a36810SAnil Ravindranath struct Scsi_Host *shost = class_to_shost(dev); 419689a36810SAnil Ravindranath struct pmcraid_instance *pinstance = 419789a36810SAnil Ravindranath (struct pmcraid_instance *)shost->hostdata; 419889a36810SAnil Ravindranath return snprintf(buf, PAGE_SIZE, "%d\n", pinstance->current_log_level); 419989a36810SAnil Ravindranath } 420089a36810SAnil Ravindranath 420189a36810SAnil Ravindranath /** 420289a36810SAnil Ravindranath * pmcraid_store_log_level - Change the adapter's error logging level 420389a36810SAnil Ravindranath * @dev: class device struct 420489a36810SAnil Ravindranath * @buf: buffer 420589a36810SAnil Ravindranath * @count: not used 420689a36810SAnil Ravindranath * 420789a36810SAnil Ravindranath * Return value: 420889a36810SAnil Ravindranath * number of bytes printed to buffer 420989a36810SAnil Ravindranath */ 421089a36810SAnil Ravindranath static ssize_t pmcraid_store_log_level( 421189a36810SAnil Ravindranath struct device *dev, 421289a36810SAnil Ravindranath struct device_attribute *attr, 421389a36810SAnil Ravindranath const char *buf, 421489a36810SAnil Ravindranath size_t count 421589a36810SAnil Ravindranath ) 421689a36810SAnil Ravindranath { 421789a36810SAnil Ravindranath struct Scsi_Host *shost; 421889a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 421989a36810SAnil Ravindranath unsigned long val; 422089a36810SAnil Ravindranath 422189a36810SAnil Ravindranath if (strict_strtoul(buf, 10, &val)) 422289a36810SAnil Ravindranath return -EINVAL; 422389a36810SAnil Ravindranath /* log-level should be from 0 to 2 */ 422489a36810SAnil Ravindranath if (val > 2) 422589a36810SAnil Ravindranath return -EINVAL; 422689a36810SAnil Ravindranath 422789a36810SAnil Ravindranath shost = class_to_shost(dev); 422889a36810SAnil Ravindranath pinstance = (struct pmcraid_instance *)shost->hostdata; 422989a36810SAnil Ravindranath pinstance->current_log_level = val; 423089a36810SAnil Ravindranath 423189a36810SAnil Ravindranath return strlen(buf); 423289a36810SAnil Ravindranath } 423389a36810SAnil Ravindranath 423489a36810SAnil Ravindranath static struct device_attribute pmcraid_log_level_attr = { 423589a36810SAnil Ravindranath .attr = { 423689a36810SAnil Ravindranath .name = "log_level", 423789a36810SAnil Ravindranath .mode = S_IRUGO | S_IWUSR, 423889a36810SAnil Ravindranath }, 423989a36810SAnil Ravindranath .show = pmcraid_show_log_level, 424089a36810SAnil Ravindranath .store = pmcraid_store_log_level, 424189a36810SAnil Ravindranath }; 424289a36810SAnil Ravindranath 424389a36810SAnil Ravindranath /** 424489a36810SAnil Ravindranath * pmcraid_show_drv_version - Display driver version 424589a36810SAnil Ravindranath * @dev: class device struct 424689a36810SAnil Ravindranath * @buf: buffer 424789a36810SAnil Ravindranath * 424889a36810SAnil Ravindranath * Return value: 424989a36810SAnil Ravindranath * number of bytes printed to buffer 425089a36810SAnil Ravindranath */ 425189a36810SAnil Ravindranath static ssize_t pmcraid_show_drv_version( 425289a36810SAnil Ravindranath struct device *dev, 425389a36810SAnil Ravindranath struct device_attribute *attr, 425489a36810SAnil Ravindranath char *buf 425589a36810SAnil Ravindranath ) 425689a36810SAnil Ravindranath { 4257a1b66665SMichal Marek return snprintf(buf, PAGE_SIZE, "version: %s\n", 4258a1b66665SMichal Marek PMCRAID_DRIVER_VERSION); 425989a36810SAnil Ravindranath } 426089a36810SAnil Ravindranath 426189a36810SAnil Ravindranath static struct device_attribute pmcraid_driver_version_attr = { 426289a36810SAnil Ravindranath .attr = { 426389a36810SAnil Ravindranath .name = "drv_version", 426489a36810SAnil Ravindranath .mode = S_IRUGO, 426589a36810SAnil Ravindranath }, 426689a36810SAnil Ravindranath .show = pmcraid_show_drv_version, 426789a36810SAnil Ravindranath }; 426889a36810SAnil Ravindranath 426989a36810SAnil Ravindranath /** 427089a36810SAnil Ravindranath * pmcraid_show_io_adapter_id - Display driver assigned adapter id 427189a36810SAnil Ravindranath * @dev: class device struct 427289a36810SAnil Ravindranath * @buf: buffer 427389a36810SAnil Ravindranath * 427489a36810SAnil Ravindranath * Return value: 427589a36810SAnil Ravindranath * number of bytes printed to buffer 427689a36810SAnil Ravindranath */ 427789a36810SAnil Ravindranath static ssize_t pmcraid_show_adapter_id( 427889a36810SAnil Ravindranath struct device *dev, 427989a36810SAnil Ravindranath struct device_attribute *attr, 428089a36810SAnil Ravindranath char *buf 428189a36810SAnil Ravindranath ) 428289a36810SAnil Ravindranath { 428389a36810SAnil Ravindranath struct Scsi_Host *shost = class_to_shost(dev); 428489a36810SAnil Ravindranath struct pmcraid_instance *pinstance = 428589a36810SAnil Ravindranath (struct pmcraid_instance *)shost->hostdata; 428689a36810SAnil Ravindranath u32 adapter_id = (pinstance->pdev->bus->number << 8) | 428789a36810SAnil Ravindranath pinstance->pdev->devfn; 428889a36810SAnil Ravindranath u32 aen_group = pmcraid_event_family.id; 428989a36810SAnil Ravindranath 429089a36810SAnil Ravindranath return snprintf(buf, PAGE_SIZE, 429189a36810SAnil Ravindranath "adapter id: %d\nminor: %d\naen group: %d\n", 429289a36810SAnil Ravindranath adapter_id, MINOR(pinstance->cdev.dev), aen_group); 429389a36810SAnil Ravindranath } 429489a36810SAnil Ravindranath 429589a36810SAnil Ravindranath static struct device_attribute pmcraid_adapter_id_attr = { 429689a36810SAnil Ravindranath .attr = { 429789a36810SAnil Ravindranath .name = "adapter_id", 429889a36810SAnil Ravindranath .mode = S_IRUGO | S_IWUSR, 429989a36810SAnil Ravindranath }, 430089a36810SAnil Ravindranath .show = pmcraid_show_adapter_id, 430189a36810SAnil Ravindranath }; 430289a36810SAnil Ravindranath 430389a36810SAnil Ravindranath static struct device_attribute *pmcraid_host_attrs[] = { 430489a36810SAnil Ravindranath &pmcraid_log_level_attr, 430589a36810SAnil Ravindranath &pmcraid_driver_version_attr, 430689a36810SAnil Ravindranath &pmcraid_adapter_id_attr, 430789a36810SAnil Ravindranath NULL, 430889a36810SAnil Ravindranath }; 430989a36810SAnil Ravindranath 431089a36810SAnil Ravindranath 431189a36810SAnil Ravindranath /* host template structure for pmcraid driver */ 431289a36810SAnil Ravindranath static struct scsi_host_template pmcraid_host_template = { 431389a36810SAnil Ravindranath .module = THIS_MODULE, 431489a36810SAnil Ravindranath .name = PMCRAID_DRIVER_NAME, 431589a36810SAnil Ravindranath .queuecommand = pmcraid_queuecommand, 431689a36810SAnil Ravindranath .eh_abort_handler = pmcraid_eh_abort_handler, 431789a36810SAnil Ravindranath .eh_bus_reset_handler = pmcraid_eh_bus_reset_handler, 431889a36810SAnil Ravindranath .eh_target_reset_handler = pmcraid_eh_target_reset_handler, 431989a36810SAnil Ravindranath .eh_device_reset_handler = pmcraid_eh_device_reset_handler, 432089a36810SAnil Ravindranath .eh_host_reset_handler = pmcraid_eh_host_reset_handler, 432189a36810SAnil Ravindranath 432289a36810SAnil Ravindranath .slave_alloc = pmcraid_slave_alloc, 432389a36810SAnil Ravindranath .slave_configure = pmcraid_slave_configure, 432489a36810SAnil Ravindranath .slave_destroy = pmcraid_slave_destroy, 432589a36810SAnil Ravindranath .change_queue_depth = pmcraid_change_queue_depth, 432689a36810SAnil Ravindranath .change_queue_type = pmcraid_change_queue_type, 432789a36810SAnil Ravindranath .can_queue = PMCRAID_MAX_IO_CMD, 432889a36810SAnil Ravindranath .this_id = -1, 432989a36810SAnil Ravindranath .sg_tablesize = PMCRAID_MAX_IOADLS, 433089a36810SAnil Ravindranath .max_sectors = PMCRAID_IOA_MAX_SECTORS, 433189a36810SAnil Ravindranath .cmd_per_lun = PMCRAID_MAX_CMD_PER_LUN, 433289a36810SAnil Ravindranath .use_clustering = ENABLE_CLUSTERING, 433389a36810SAnil Ravindranath .shost_attrs = pmcraid_host_attrs, 433489a36810SAnil Ravindranath .proc_name = PMCRAID_DRIVER_NAME 433589a36810SAnil Ravindranath }; 433689a36810SAnil Ravindranath 4337c20c4267SAnil Ravindranath /* 4338c20c4267SAnil Ravindranath * pmcraid_isr_msix - implements MSI-X interrupt handling routine 4339c20c4267SAnil Ravindranath * @irq: interrupt vector number 4340c20c4267SAnil Ravindranath * @dev_id: pointer hrrq_vector 434189a36810SAnil Ravindranath * 434289a36810SAnil Ravindranath * Return Value 4343c20c4267SAnil Ravindranath * IRQ_HANDLED if interrupt is handled or IRQ_NONE if ignored 434489a36810SAnil Ravindranath */ 434589a36810SAnil Ravindranath 4346c20c4267SAnil Ravindranath static irqreturn_t pmcraid_isr_msix(int irq, void *dev_id) 4347c20c4267SAnil Ravindranath { 4348c20c4267SAnil Ravindranath struct pmcraid_isr_param *hrrq_vector; 4349c20c4267SAnil Ravindranath struct pmcraid_instance *pinstance; 4350c20c4267SAnil Ravindranath unsigned long lock_flags; 4351c20c4267SAnil Ravindranath u32 intrs_val; 4352c20c4267SAnil Ravindranath int hrrq_id; 4353c20c4267SAnil Ravindranath 4354c20c4267SAnil Ravindranath hrrq_vector = (struct pmcraid_isr_param *)dev_id; 4355c20c4267SAnil Ravindranath hrrq_id = hrrq_vector->hrrq_id; 4356c20c4267SAnil Ravindranath pinstance = hrrq_vector->drv_inst; 4357c20c4267SAnil Ravindranath 4358c20c4267SAnil Ravindranath if (!hrrq_id) { 4359c20c4267SAnil Ravindranath /* Read the interrupt */ 4360c20c4267SAnil Ravindranath intrs_val = pmcraid_read_interrupts(pinstance); 4361c20c4267SAnil Ravindranath if (intrs_val && 4362c20c4267SAnil Ravindranath ((ioread32(pinstance->int_regs.host_ioa_interrupt_reg) 4363c20c4267SAnil Ravindranath & DOORBELL_INTR_MSIX_CLR) == 0)) { 4364c20c4267SAnil Ravindranath /* Any error interrupts including unit_check, 4365c20c4267SAnil Ravindranath * initiate IOA reset.In case of unit check indicate 4366c20c4267SAnil Ravindranath * to reset_sequence that IOA unit checked and prepare 4367c20c4267SAnil Ravindranath * for a dump during reset sequence 4368c20c4267SAnil Ravindranath */ 4369c20c4267SAnil Ravindranath if (intrs_val & PMCRAID_ERROR_INTERRUPTS) { 4370c20c4267SAnil Ravindranath if (intrs_val & INTRS_IOA_UNIT_CHECK) 4371c20c4267SAnil Ravindranath pinstance->ioa_unit_check = 1; 4372c20c4267SAnil Ravindranath 4373c20c4267SAnil Ravindranath pmcraid_err("ISR: error interrupts: %x \ 4374c20c4267SAnil Ravindranath initiating reset\n", intrs_val); 4375c20c4267SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, 4376c20c4267SAnil Ravindranath lock_flags); 4377c20c4267SAnil Ravindranath pmcraid_initiate_reset(pinstance); 4378c20c4267SAnil Ravindranath spin_unlock_irqrestore( 4379c20c4267SAnil Ravindranath pinstance->host->host_lock, 4380c20c4267SAnil Ravindranath lock_flags); 4381c20c4267SAnil Ravindranath } 4382c20c4267SAnil Ravindranath /* If interrupt was as part of the ioa initialization, 4383c20c4267SAnil Ravindranath * clear it. Delete the timer and wakeup the 4384c20c4267SAnil Ravindranath * reset engine to proceed with reset sequence 4385c20c4267SAnil Ravindranath */ 4386c20c4267SAnil Ravindranath if (intrs_val & INTRS_TRANSITION_TO_OPERATIONAL) 4387c20c4267SAnil Ravindranath pmcraid_clr_trans_op(pinstance); 4388c20c4267SAnil Ravindranath 4389c20c4267SAnil Ravindranath /* Clear the interrupt register by writing 4390c20c4267SAnil Ravindranath * to host to ioa doorbell. Once done 4391c20c4267SAnil Ravindranath * FW will clear the interrupt. 4392c20c4267SAnil Ravindranath */ 4393c20c4267SAnil Ravindranath iowrite32(DOORBELL_INTR_MSIX_CLR, 4394c20c4267SAnil Ravindranath pinstance->int_regs.host_ioa_interrupt_reg); 4395c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.host_ioa_interrupt_reg); 4396c20c4267SAnil Ravindranath 4397c20c4267SAnil Ravindranath 4398c20c4267SAnil Ravindranath } 4399c20c4267SAnil Ravindranath } 4400c20c4267SAnil Ravindranath 440189a36810SAnil Ravindranath tasklet_schedule(&(pinstance->isr_tasklet[hrrq_id])); 4402c20c4267SAnil Ravindranath 4403c20c4267SAnil Ravindranath return IRQ_HANDLED; 440489a36810SAnil Ravindranath } 440589a36810SAnil Ravindranath 440689a36810SAnil Ravindranath /** 4407c20c4267SAnil Ravindranath * pmcraid_isr - implements legacy interrupt handling routine 440889a36810SAnil Ravindranath * 440989a36810SAnil Ravindranath * @irq: interrupt vector number 441089a36810SAnil Ravindranath * @dev_id: pointer hrrq_vector 441189a36810SAnil Ravindranath * 441289a36810SAnil Ravindranath * Return Value 441389a36810SAnil Ravindranath * IRQ_HANDLED if interrupt is handled or IRQ_NONE if ignored 441489a36810SAnil Ravindranath */ 441589a36810SAnil Ravindranath static irqreturn_t pmcraid_isr(int irq, void *dev_id) 441689a36810SAnil Ravindranath { 441789a36810SAnil Ravindranath struct pmcraid_isr_param *hrrq_vector; 441889a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 441989a36810SAnil Ravindranath u32 intrs; 4420c20c4267SAnil Ravindranath unsigned long lock_flags; 4421c20c4267SAnil Ravindranath int hrrq_id = 0; 442289a36810SAnil Ravindranath 442389a36810SAnil Ravindranath /* In case of legacy interrupt mode where interrupts are shared across 442489a36810SAnil Ravindranath * isrs, it may be possible that the current interrupt is not from IOA 442589a36810SAnil Ravindranath */ 442689a36810SAnil Ravindranath if (!dev_id) { 442789a36810SAnil Ravindranath printk(KERN_INFO "%s(): NULL host pointer\n", __func__); 442889a36810SAnil Ravindranath return IRQ_NONE; 442989a36810SAnil Ravindranath } 443089a36810SAnil Ravindranath hrrq_vector = (struct pmcraid_isr_param *)dev_id; 443189a36810SAnil Ravindranath pinstance = hrrq_vector->drv_inst; 443289a36810SAnil Ravindranath 443389a36810SAnil Ravindranath intrs = pmcraid_read_interrupts(pinstance); 443489a36810SAnil Ravindranath 4435c20c4267SAnil Ravindranath if (unlikely((intrs & PMCRAID_PCI_INTERRUPTS) == 0)) 443689a36810SAnil Ravindranath return IRQ_NONE; 443789a36810SAnil Ravindranath 443889a36810SAnil Ravindranath /* Any error interrupts including unit_check, initiate IOA reset. 443989a36810SAnil Ravindranath * In case of unit check indicate to reset_sequence that IOA unit 444089a36810SAnil Ravindranath * checked and prepare for a dump during reset sequence 444189a36810SAnil Ravindranath */ 444289a36810SAnil Ravindranath if (intrs & PMCRAID_ERROR_INTERRUPTS) { 444389a36810SAnil Ravindranath 444489a36810SAnil Ravindranath if (intrs & INTRS_IOA_UNIT_CHECK) 444589a36810SAnil Ravindranath pinstance->ioa_unit_check = 1; 444689a36810SAnil Ravindranath 444789a36810SAnil Ravindranath iowrite32(intrs, 444889a36810SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_clr_reg); 444989a36810SAnil Ravindranath pmcraid_err("ISR: error interrupts: %x initiating reset\n", 445089a36810SAnil Ravindranath intrs); 4451c20c4267SAnil Ravindranath intrs = ioread32( 4452c20c4267SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_clr_reg); 4453c20c4267SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 445489a36810SAnil Ravindranath pmcraid_initiate_reset(pinstance); 445589a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 4456c20c4267SAnil Ravindranath } else { 4457c20c4267SAnil Ravindranath /* If interrupt was as part of the ioa initialization, 4458c20c4267SAnil Ravindranath * clear. Delete the timer and wakeup the 4459c20c4267SAnil Ravindranath * reset engine to proceed with reset sequence 4460c20c4267SAnil Ravindranath */ 4461c20c4267SAnil Ravindranath if (intrs & INTRS_TRANSITION_TO_OPERATIONAL) { 4462c20c4267SAnil Ravindranath pmcraid_clr_trans_op(pinstance); 4463c20c4267SAnil Ravindranath } else { 4464c20c4267SAnil Ravindranath iowrite32(intrs, 4465c20c4267SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_clr_reg); 4466c20c4267SAnil Ravindranath ioread32( 4467c20c4267SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_clr_reg); 4468c20c4267SAnil Ravindranath 4469c20c4267SAnil Ravindranath tasklet_schedule( 4470c20c4267SAnil Ravindranath &(pinstance->isr_tasklet[hrrq_id])); 4471c20c4267SAnil Ravindranath } 4472c20c4267SAnil Ravindranath } 447389a36810SAnil Ravindranath 447489a36810SAnil Ravindranath return IRQ_HANDLED; 447589a36810SAnil Ravindranath } 447689a36810SAnil Ravindranath 447789a36810SAnil Ravindranath 447889a36810SAnil Ravindranath /** 447989a36810SAnil Ravindranath * pmcraid_worker_function - worker thread function 448089a36810SAnil Ravindranath * 448189a36810SAnil Ravindranath * @workp: pointer to struct work queue 448289a36810SAnil Ravindranath * 448389a36810SAnil Ravindranath * Return Value 448489a36810SAnil Ravindranath * None 448589a36810SAnil Ravindranath */ 448689a36810SAnil Ravindranath 448789a36810SAnil Ravindranath static void pmcraid_worker_function(struct work_struct *workp) 448889a36810SAnil Ravindranath { 448989a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 449089a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 449189a36810SAnil Ravindranath struct pmcraid_resource_entry *temp; 449289a36810SAnil Ravindranath struct scsi_device *sdev; 449389a36810SAnil Ravindranath unsigned long lock_flags; 449489a36810SAnil Ravindranath unsigned long host_lock_flags; 4495c20c4267SAnil Ravindranath u16 fw_version; 449689a36810SAnil Ravindranath u8 bus, target, lun; 449789a36810SAnil Ravindranath 449889a36810SAnil Ravindranath pinstance = container_of(workp, struct pmcraid_instance, worker_q); 449989a36810SAnil Ravindranath /* add resources only after host is added into system */ 450089a36810SAnil Ravindranath if (!atomic_read(&pinstance->expose_resources)) 450189a36810SAnil Ravindranath return; 450289a36810SAnil Ravindranath 4503c20c4267SAnil Ravindranath fw_version = be16_to_cpu(pinstance->inq_data->fw_version); 4504c20c4267SAnil Ravindranath 450589a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->resource_lock, lock_flags); 450689a36810SAnil Ravindranath list_for_each_entry_safe(res, temp, &pinstance->used_res_q, queue) { 450789a36810SAnil Ravindranath 450889a36810SAnil Ravindranath if (res->change_detected == RES_CHANGE_DEL && res->scsi_dev) { 450989a36810SAnil Ravindranath sdev = res->scsi_dev; 451089a36810SAnil Ravindranath 451189a36810SAnil Ravindranath /* host_lock must be held before calling 451289a36810SAnil Ravindranath * scsi_device_get 451389a36810SAnil Ravindranath */ 451489a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, 451589a36810SAnil Ravindranath host_lock_flags); 451689a36810SAnil Ravindranath if (!scsi_device_get(sdev)) { 451789a36810SAnil Ravindranath spin_unlock_irqrestore( 451889a36810SAnil Ravindranath pinstance->host->host_lock, 451989a36810SAnil Ravindranath host_lock_flags); 452089a36810SAnil Ravindranath pmcraid_info("deleting %x from midlayer\n", 452189a36810SAnil Ravindranath res->cfg_entry.resource_address); 452289a36810SAnil Ravindranath list_move_tail(&res->queue, 452389a36810SAnil Ravindranath &pinstance->free_res_q); 452489a36810SAnil Ravindranath spin_unlock_irqrestore( 452589a36810SAnil Ravindranath &pinstance->resource_lock, 452689a36810SAnil Ravindranath lock_flags); 452789a36810SAnil Ravindranath scsi_remove_device(sdev); 452889a36810SAnil Ravindranath scsi_device_put(sdev); 452989a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->resource_lock, 453089a36810SAnil Ravindranath lock_flags); 453189a36810SAnil Ravindranath res->change_detected = 0; 453289a36810SAnil Ravindranath } else { 453389a36810SAnil Ravindranath spin_unlock_irqrestore( 453489a36810SAnil Ravindranath pinstance->host->host_lock, 453589a36810SAnil Ravindranath host_lock_flags); 453689a36810SAnil Ravindranath } 453789a36810SAnil Ravindranath } 453889a36810SAnil Ravindranath } 453989a36810SAnil Ravindranath 454089a36810SAnil Ravindranath list_for_each_entry(res, &pinstance->used_res_q, queue) { 454189a36810SAnil Ravindranath 454289a36810SAnil Ravindranath if (res->change_detected == RES_CHANGE_ADD) { 454389a36810SAnil Ravindranath 4544c20c4267SAnil Ravindranath if (!pmcraid_expose_resource(fw_version, 4545c20c4267SAnil Ravindranath &res->cfg_entry)) 454689a36810SAnil Ravindranath continue; 454789a36810SAnil Ravindranath 454889a36810SAnil Ravindranath if (RES_IS_VSET(res->cfg_entry)) { 454989a36810SAnil Ravindranath bus = PMCRAID_VSET_BUS_ID; 4550c20c4267SAnil Ravindranath if (fw_version <= PMCRAID_FW_VERSION_1) 455189a36810SAnil Ravindranath target = res->cfg_entry.unique_flags1; 4552c20c4267SAnil Ravindranath else 4553c20c4267SAnil Ravindranath target = res->cfg_entry.array_id & 0xFF; 455489a36810SAnil Ravindranath lun = PMCRAID_VSET_LUN_ID; 455589a36810SAnil Ravindranath } else { 455689a36810SAnil Ravindranath bus = PMCRAID_PHYS_BUS_ID; 455789a36810SAnil Ravindranath target = 455889a36810SAnil Ravindranath RES_TARGET( 455989a36810SAnil Ravindranath res->cfg_entry.resource_address); 456089a36810SAnil Ravindranath lun = RES_LUN(res->cfg_entry.resource_address); 456189a36810SAnil Ravindranath } 456289a36810SAnil Ravindranath 456389a36810SAnil Ravindranath res->change_detected = 0; 456489a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, 456589a36810SAnil Ravindranath lock_flags); 456689a36810SAnil Ravindranath scsi_add_device(pinstance->host, bus, target, lun); 456789a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->resource_lock, 456889a36810SAnil Ravindranath lock_flags); 456989a36810SAnil Ravindranath } 457089a36810SAnil Ravindranath } 457189a36810SAnil Ravindranath 457289a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); 457389a36810SAnil Ravindranath } 457489a36810SAnil Ravindranath 457589a36810SAnil Ravindranath /** 457689a36810SAnil Ravindranath * pmcraid_tasklet_function - Tasklet function 457789a36810SAnil Ravindranath * 457889a36810SAnil Ravindranath * @instance: pointer to msix param structure 457989a36810SAnil Ravindranath * 458089a36810SAnil Ravindranath * Return Value 458189a36810SAnil Ravindranath * None 458289a36810SAnil Ravindranath */ 4583c20c4267SAnil Ravindranath static void pmcraid_tasklet_function(unsigned long instance) 458489a36810SAnil Ravindranath { 458589a36810SAnil Ravindranath struct pmcraid_isr_param *hrrq_vector; 458689a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 458789a36810SAnil Ravindranath unsigned long hrrq_lock_flags; 458889a36810SAnil Ravindranath unsigned long pending_lock_flags; 458989a36810SAnil Ravindranath unsigned long host_lock_flags; 459089a36810SAnil Ravindranath spinlock_t *lockp; /* hrrq buffer lock */ 459189a36810SAnil Ravindranath int id; 459289a36810SAnil Ravindranath __le32 resp; 459389a36810SAnil Ravindranath 459489a36810SAnil Ravindranath hrrq_vector = (struct pmcraid_isr_param *)instance; 459589a36810SAnil Ravindranath pinstance = hrrq_vector->drv_inst; 459689a36810SAnil Ravindranath id = hrrq_vector->hrrq_id; 459789a36810SAnil Ravindranath lockp = &(pinstance->hrrq_lock[id]); 459889a36810SAnil Ravindranath 459989a36810SAnil Ravindranath /* loop through each of the commands responded by IOA. Each HRRQ buf is 460089a36810SAnil Ravindranath * protected by its own lock. Traversals must be done within this lock 460189a36810SAnil Ravindranath * as there may be multiple tasklets running on multiple CPUs. Note 460289a36810SAnil Ravindranath * that the lock is held just for picking up the response handle and 460389a36810SAnil Ravindranath * manipulating hrrq_curr/toggle_bit values. 460489a36810SAnil Ravindranath */ 460589a36810SAnil Ravindranath spin_lock_irqsave(lockp, hrrq_lock_flags); 460689a36810SAnil Ravindranath 460789a36810SAnil Ravindranath resp = le32_to_cpu(*(pinstance->hrrq_curr[id])); 460889a36810SAnil Ravindranath 460989a36810SAnil Ravindranath while ((resp & HRRQ_TOGGLE_BIT) == 461089a36810SAnil Ravindranath pinstance->host_toggle_bit[id]) { 461189a36810SAnil Ravindranath 461289a36810SAnil Ravindranath int cmd_index = resp >> 2; 461389a36810SAnil Ravindranath struct pmcraid_cmd *cmd = NULL; 461489a36810SAnil Ravindranath 461589a36810SAnil Ravindranath if (pinstance->hrrq_curr[id] < pinstance->hrrq_end[id]) { 461689a36810SAnil Ravindranath pinstance->hrrq_curr[id]++; 461789a36810SAnil Ravindranath } else { 461889a36810SAnil Ravindranath pinstance->hrrq_curr[id] = pinstance->hrrq_start[id]; 461989a36810SAnil Ravindranath pinstance->host_toggle_bit[id] ^= 1u; 462089a36810SAnil Ravindranath } 462189a36810SAnil Ravindranath 4622c20c4267SAnil Ravindranath if (cmd_index >= PMCRAID_MAX_CMD) { 4623c20c4267SAnil Ravindranath /* In case of invalid response handle, log message */ 4624c20c4267SAnil Ravindranath pmcraid_err("Invalid response handle %d\n", cmd_index); 4625c20c4267SAnil Ravindranath resp = le32_to_cpu(*(pinstance->hrrq_curr[id])); 4626c20c4267SAnil Ravindranath continue; 4627c20c4267SAnil Ravindranath } 4628c20c4267SAnil Ravindranath 4629c20c4267SAnil Ravindranath cmd = pinstance->cmd_list[cmd_index]; 463089a36810SAnil Ravindranath spin_unlock_irqrestore(lockp, hrrq_lock_flags); 463189a36810SAnil Ravindranath 463289a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->pending_pool_lock, 463389a36810SAnil Ravindranath pending_lock_flags); 463489a36810SAnil Ravindranath list_del(&cmd->free_list); 463589a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->pending_pool_lock, 463689a36810SAnil Ravindranath pending_lock_flags); 463789a36810SAnil Ravindranath del_timer(&cmd->timer); 463889a36810SAnil Ravindranath atomic_dec(&pinstance->outstanding_cmds); 463989a36810SAnil Ravindranath 464089a36810SAnil Ravindranath if (cmd->cmd_done == pmcraid_ioa_reset) { 464189a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, 464289a36810SAnil Ravindranath host_lock_flags); 464389a36810SAnil Ravindranath cmd->cmd_done(cmd); 464489a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 464589a36810SAnil Ravindranath host_lock_flags); 464689a36810SAnil Ravindranath } else if (cmd->cmd_done != NULL) { 464789a36810SAnil Ravindranath cmd->cmd_done(cmd); 464889a36810SAnil Ravindranath } 464989a36810SAnil Ravindranath /* loop over until we are done with all responses */ 465089a36810SAnil Ravindranath spin_lock_irqsave(lockp, hrrq_lock_flags); 465189a36810SAnil Ravindranath resp = le32_to_cpu(*(pinstance->hrrq_curr[id])); 465289a36810SAnil Ravindranath } 465389a36810SAnil Ravindranath 465489a36810SAnil Ravindranath spin_unlock_irqrestore(lockp, hrrq_lock_flags); 465589a36810SAnil Ravindranath } 465689a36810SAnil Ravindranath 465789a36810SAnil Ravindranath /** 465889a36810SAnil Ravindranath * pmcraid_unregister_interrupt_handler - de-register interrupts handlers 465989a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 466089a36810SAnil Ravindranath * 466189a36810SAnil Ravindranath * This routine un-registers registered interrupt handler and 466289a36810SAnil Ravindranath * also frees irqs/vectors. 466389a36810SAnil Ravindranath * 466489a36810SAnil Ravindranath * Retun Value 466589a36810SAnil Ravindranath * None 466689a36810SAnil Ravindranath */ 466789a36810SAnil Ravindranath static 466889a36810SAnil Ravindranath void pmcraid_unregister_interrupt_handler(struct pmcraid_instance *pinstance) 466989a36810SAnil Ravindranath { 4670c20c4267SAnil Ravindranath int i; 4671c20c4267SAnil Ravindranath 4672c20c4267SAnil Ravindranath for (i = 0; i < pinstance->num_hrrq; i++) 4673c20c4267SAnil Ravindranath free_irq(pinstance->hrrq_vector[i].vector, 4674c20c4267SAnil Ravindranath &(pinstance->hrrq_vector[i])); 4675c20c4267SAnil Ravindranath 4676c20c4267SAnil Ravindranath if (pinstance->interrupt_mode) { 4677c20c4267SAnil Ravindranath pci_disable_msix(pinstance->pdev); 4678c20c4267SAnil Ravindranath pinstance->interrupt_mode = 0; 4679c20c4267SAnil Ravindranath } 468089a36810SAnil Ravindranath } 468189a36810SAnil Ravindranath 468289a36810SAnil Ravindranath /** 468389a36810SAnil Ravindranath * pmcraid_register_interrupt_handler - registers interrupt handler 468489a36810SAnil Ravindranath * @pinstance: pointer to per-adapter instance structure 468589a36810SAnil Ravindranath * 468689a36810SAnil Ravindranath * Return Value 468789a36810SAnil Ravindranath * 0 on success, non-zero error code otherwise. 468889a36810SAnil Ravindranath */ 468989a36810SAnil Ravindranath static int 469089a36810SAnil Ravindranath pmcraid_register_interrupt_handler(struct pmcraid_instance *pinstance) 469189a36810SAnil Ravindranath { 4692c20c4267SAnil Ravindranath int rc; 469389a36810SAnil Ravindranath struct pci_dev *pdev = pinstance->pdev; 469489a36810SAnil Ravindranath 46955da61410SAnil Ravindranath if ((pmcraid_enable_msix) && 46965da61410SAnil Ravindranath (pci_find_capability(pdev, PCI_CAP_ID_MSIX))) { 4697c20c4267SAnil Ravindranath int num_hrrq = PMCRAID_NUM_MSIX_VECTORS; 4698c20c4267SAnil Ravindranath struct msix_entry entries[PMCRAID_NUM_MSIX_VECTORS]; 4699c20c4267SAnil Ravindranath int i; 4700c20c4267SAnil Ravindranath for (i = 0; i < PMCRAID_NUM_MSIX_VECTORS; i++) 4701c20c4267SAnil Ravindranath entries[i].entry = i; 4702c20c4267SAnil Ravindranath 4703c20c4267SAnil Ravindranath rc = pci_enable_msix(pdev, entries, num_hrrq); 4704c20c4267SAnil Ravindranath if (rc < 0) 4705c20c4267SAnil Ravindranath goto pmcraid_isr_legacy; 4706c20c4267SAnil Ravindranath 4707c20c4267SAnil Ravindranath /* Check how many MSIX vectors are allocated and register 4708c20c4267SAnil Ravindranath * msi-x handlers for each of them giving appropriate buffer 4709c20c4267SAnil Ravindranath */ 4710c20c4267SAnil Ravindranath if (rc > 0) { 4711c20c4267SAnil Ravindranath num_hrrq = rc; 4712c20c4267SAnil Ravindranath if (pci_enable_msix(pdev, entries, num_hrrq)) 4713c20c4267SAnil Ravindranath goto pmcraid_isr_legacy; 4714c20c4267SAnil Ravindranath } 4715c20c4267SAnil Ravindranath 4716c20c4267SAnil Ravindranath for (i = 0; i < num_hrrq; i++) { 4717c20c4267SAnil Ravindranath pinstance->hrrq_vector[i].hrrq_id = i; 4718c20c4267SAnil Ravindranath pinstance->hrrq_vector[i].drv_inst = pinstance; 4719c20c4267SAnil Ravindranath pinstance->hrrq_vector[i].vector = entries[i].vector; 4720c20c4267SAnil Ravindranath rc = request_irq(pinstance->hrrq_vector[i].vector, 4721c20c4267SAnil Ravindranath pmcraid_isr_msix, 0, 4722c20c4267SAnil Ravindranath PMCRAID_DRIVER_NAME, 4723c20c4267SAnil Ravindranath &(pinstance->hrrq_vector[i])); 4724c20c4267SAnil Ravindranath 4725c20c4267SAnil Ravindranath if (rc) { 4726c20c4267SAnil Ravindranath int j; 4727c20c4267SAnil Ravindranath for (j = 0; j < i; j++) 4728c20c4267SAnil Ravindranath free_irq(entries[j].vector, 4729c20c4267SAnil Ravindranath &(pinstance->hrrq_vector[j])); 4730c20c4267SAnil Ravindranath pci_disable_msix(pdev); 4731c20c4267SAnil Ravindranath goto pmcraid_isr_legacy; 4732c20c4267SAnil Ravindranath } 4733c20c4267SAnil Ravindranath } 4734c20c4267SAnil Ravindranath 4735c20c4267SAnil Ravindranath pinstance->num_hrrq = num_hrrq; 4736c20c4267SAnil Ravindranath pinstance->interrupt_mode = 1; 4737c20c4267SAnil Ravindranath iowrite32(DOORBELL_INTR_MODE_MSIX, 4738c20c4267SAnil Ravindranath pinstance->int_regs.host_ioa_interrupt_reg); 4739c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.host_ioa_interrupt_reg); 4740c20c4267SAnil Ravindranath goto pmcraid_isr_out; 4741c20c4267SAnil Ravindranath } 4742c20c4267SAnil Ravindranath 4743c20c4267SAnil Ravindranath pmcraid_isr_legacy: 4744c20c4267SAnil Ravindranath /* If MSI-X registration failed fallback to legacy mode, where 4745c20c4267SAnil Ravindranath * only one hrrq entry will be used 4746c20c4267SAnil Ravindranath */ 474789a36810SAnil Ravindranath pinstance->hrrq_vector[0].hrrq_id = 0; 474889a36810SAnil Ravindranath pinstance->hrrq_vector[0].drv_inst = pinstance; 4749c20c4267SAnil Ravindranath pinstance->hrrq_vector[0].vector = pdev->irq; 475089a36810SAnil Ravindranath pinstance->num_hrrq = 1; 4751c20c4267SAnil Ravindranath rc = 0; 4752c20c4267SAnil Ravindranath 4753c20c4267SAnil Ravindranath rc = request_irq(pdev->irq, pmcraid_isr, IRQF_SHARED, 475489a36810SAnil Ravindranath PMCRAID_DRIVER_NAME, &pinstance->hrrq_vector[0]); 4755c20c4267SAnil Ravindranath pmcraid_isr_out: 4756c20c4267SAnil Ravindranath return rc; 475789a36810SAnil Ravindranath } 475889a36810SAnil Ravindranath 475989a36810SAnil Ravindranath /** 476089a36810SAnil Ravindranath * pmcraid_release_cmd_blocks - release buufers allocated for command blocks 476189a36810SAnil Ravindranath * @pinstance: per adapter instance structure pointer 476289a36810SAnil Ravindranath * @max_index: number of buffer blocks to release 476389a36810SAnil Ravindranath * 476489a36810SAnil Ravindranath * Return Value 476589a36810SAnil Ravindranath * None 476689a36810SAnil Ravindranath */ 476789a36810SAnil Ravindranath static void 476889a36810SAnil Ravindranath pmcraid_release_cmd_blocks(struct pmcraid_instance *pinstance, int max_index) 476989a36810SAnil Ravindranath { 477089a36810SAnil Ravindranath int i; 477189a36810SAnil Ravindranath for (i = 0; i < max_index; i++) { 477289a36810SAnil Ravindranath kmem_cache_free(pinstance->cmd_cachep, pinstance->cmd_list[i]); 477389a36810SAnil Ravindranath pinstance->cmd_list[i] = NULL; 477489a36810SAnil Ravindranath } 477589a36810SAnil Ravindranath kmem_cache_destroy(pinstance->cmd_cachep); 477689a36810SAnil Ravindranath pinstance->cmd_cachep = NULL; 477789a36810SAnil Ravindranath } 477889a36810SAnil Ravindranath 477989a36810SAnil Ravindranath /** 478089a36810SAnil Ravindranath * pmcraid_release_control_blocks - releases buffers alloced for control blocks 478189a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 478289a36810SAnil Ravindranath * @max_index: number of buffers (from 0 onwards) to release 478389a36810SAnil Ravindranath * 478489a36810SAnil Ravindranath * This function assumes that the command blocks for which control blocks are 478589a36810SAnil Ravindranath * linked are not released. 478689a36810SAnil Ravindranath * 478789a36810SAnil Ravindranath * Return Value 478889a36810SAnil Ravindranath * None 478989a36810SAnil Ravindranath */ 479089a36810SAnil Ravindranath static void 479189a36810SAnil Ravindranath pmcraid_release_control_blocks( 479289a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 479389a36810SAnil Ravindranath int max_index 479489a36810SAnil Ravindranath ) 479589a36810SAnil Ravindranath { 479689a36810SAnil Ravindranath int i; 479789a36810SAnil Ravindranath 479889a36810SAnil Ravindranath if (pinstance->control_pool == NULL) 479989a36810SAnil Ravindranath return; 480089a36810SAnil Ravindranath 480189a36810SAnil Ravindranath for (i = 0; i < max_index; i++) { 480289a36810SAnil Ravindranath pci_pool_free(pinstance->control_pool, 480389a36810SAnil Ravindranath pinstance->cmd_list[i]->ioa_cb, 480489a36810SAnil Ravindranath pinstance->cmd_list[i]->ioa_cb_bus_addr); 480589a36810SAnil Ravindranath pinstance->cmd_list[i]->ioa_cb = NULL; 480689a36810SAnil Ravindranath pinstance->cmd_list[i]->ioa_cb_bus_addr = 0; 480789a36810SAnil Ravindranath } 480889a36810SAnil Ravindranath pci_pool_destroy(pinstance->control_pool); 480989a36810SAnil Ravindranath pinstance->control_pool = NULL; 481089a36810SAnil Ravindranath } 481189a36810SAnil Ravindranath 481289a36810SAnil Ravindranath /** 481389a36810SAnil Ravindranath * pmcraid_allocate_cmd_blocks - allocate memory for cmd block structures 481489a36810SAnil Ravindranath * @pinstance - pointer to per adapter instance structure 481589a36810SAnil Ravindranath * 481689a36810SAnil Ravindranath * Allocates memory for command blocks using kernel slab allocator. 481789a36810SAnil Ravindranath * 481889a36810SAnil Ravindranath * Return Value 481989a36810SAnil Ravindranath * 0 in case of success; -ENOMEM in case of failure 482089a36810SAnil Ravindranath */ 482189a36810SAnil Ravindranath static int __devinit 482289a36810SAnil Ravindranath pmcraid_allocate_cmd_blocks(struct pmcraid_instance *pinstance) 482389a36810SAnil Ravindranath { 482489a36810SAnil Ravindranath int i; 482589a36810SAnil Ravindranath 482689a36810SAnil Ravindranath sprintf(pinstance->cmd_pool_name, "pmcraid_cmd_pool_%d", 482789a36810SAnil Ravindranath pinstance->host->unique_id); 482889a36810SAnil Ravindranath 482989a36810SAnil Ravindranath 483089a36810SAnil Ravindranath pinstance->cmd_cachep = kmem_cache_create( 483189a36810SAnil Ravindranath pinstance->cmd_pool_name, 483289a36810SAnil Ravindranath sizeof(struct pmcraid_cmd), 0, 483389a36810SAnil Ravindranath SLAB_HWCACHE_ALIGN, NULL); 483489a36810SAnil Ravindranath if (!pinstance->cmd_cachep) 483589a36810SAnil Ravindranath return -ENOMEM; 483689a36810SAnil Ravindranath 483789a36810SAnil Ravindranath for (i = 0; i < PMCRAID_MAX_CMD; i++) { 483889a36810SAnil Ravindranath pinstance->cmd_list[i] = 483989a36810SAnil Ravindranath kmem_cache_alloc(pinstance->cmd_cachep, GFP_KERNEL); 484089a36810SAnil Ravindranath if (!pinstance->cmd_list[i]) { 484189a36810SAnil Ravindranath pmcraid_release_cmd_blocks(pinstance, i); 484289a36810SAnil Ravindranath return -ENOMEM; 484389a36810SAnil Ravindranath } 484489a36810SAnil Ravindranath } 484589a36810SAnil Ravindranath return 0; 484689a36810SAnil Ravindranath } 484789a36810SAnil Ravindranath 484889a36810SAnil Ravindranath /** 484989a36810SAnil Ravindranath * pmcraid_allocate_control_blocks - allocates memory control blocks 485089a36810SAnil Ravindranath * @pinstance : pointer to per adapter instance structure 485189a36810SAnil Ravindranath * 485289a36810SAnil Ravindranath * This function allocates PCI memory for DMAable buffers like IOARCB, IOADLs 485389a36810SAnil Ravindranath * and IOASAs. This is called after command blocks are already allocated. 485489a36810SAnil Ravindranath * 485589a36810SAnil Ravindranath * Return Value 485689a36810SAnil Ravindranath * 0 in case it can allocate all control blocks, otherwise -ENOMEM 485789a36810SAnil Ravindranath */ 485889a36810SAnil Ravindranath static int __devinit 485989a36810SAnil Ravindranath pmcraid_allocate_control_blocks(struct pmcraid_instance *pinstance) 486089a36810SAnil Ravindranath { 486189a36810SAnil Ravindranath int i; 486289a36810SAnil Ravindranath 486389a36810SAnil Ravindranath sprintf(pinstance->ctl_pool_name, "pmcraid_control_pool_%d", 486489a36810SAnil Ravindranath pinstance->host->unique_id); 486589a36810SAnil Ravindranath 486689a36810SAnil Ravindranath pinstance->control_pool = 486789a36810SAnil Ravindranath pci_pool_create(pinstance->ctl_pool_name, 486889a36810SAnil Ravindranath pinstance->pdev, 486989a36810SAnil Ravindranath sizeof(struct pmcraid_control_block), 487089a36810SAnil Ravindranath PMCRAID_IOARCB_ALIGNMENT, 0); 487189a36810SAnil Ravindranath 487289a36810SAnil Ravindranath if (!pinstance->control_pool) 487389a36810SAnil Ravindranath return -ENOMEM; 487489a36810SAnil Ravindranath 487589a36810SAnil Ravindranath for (i = 0; i < PMCRAID_MAX_CMD; i++) { 487689a36810SAnil Ravindranath pinstance->cmd_list[i]->ioa_cb = 487789a36810SAnil Ravindranath pci_pool_alloc( 487889a36810SAnil Ravindranath pinstance->control_pool, 487989a36810SAnil Ravindranath GFP_KERNEL, 488089a36810SAnil Ravindranath &(pinstance->cmd_list[i]->ioa_cb_bus_addr)); 488189a36810SAnil Ravindranath 488289a36810SAnil Ravindranath if (!pinstance->cmd_list[i]->ioa_cb) { 488389a36810SAnil Ravindranath pmcraid_release_control_blocks(pinstance, i); 488489a36810SAnil Ravindranath return -ENOMEM; 488589a36810SAnil Ravindranath } 488689a36810SAnil Ravindranath memset(pinstance->cmd_list[i]->ioa_cb, 0, 488789a36810SAnil Ravindranath sizeof(struct pmcraid_control_block)); 488889a36810SAnil Ravindranath } 488989a36810SAnil Ravindranath return 0; 489089a36810SAnil Ravindranath } 489189a36810SAnil Ravindranath 489289a36810SAnil Ravindranath /** 489389a36810SAnil Ravindranath * pmcraid_release_host_rrqs - release memory allocated for hrrq buffer(s) 489489a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 489589a36810SAnil Ravindranath * @maxindex: size of hrrq buffer pointer array 489689a36810SAnil Ravindranath * 489789a36810SAnil Ravindranath * Return Value 489889a36810SAnil Ravindranath * None 489989a36810SAnil Ravindranath */ 490089a36810SAnil Ravindranath static void 490189a36810SAnil Ravindranath pmcraid_release_host_rrqs(struct pmcraid_instance *pinstance, int maxindex) 490289a36810SAnil Ravindranath { 490389a36810SAnil Ravindranath int i; 490489a36810SAnil Ravindranath for (i = 0; i < maxindex; i++) { 490589a36810SAnil Ravindranath 490689a36810SAnil Ravindranath pci_free_consistent(pinstance->pdev, 490789a36810SAnil Ravindranath HRRQ_ENTRY_SIZE * PMCRAID_MAX_CMD, 490889a36810SAnil Ravindranath pinstance->hrrq_start[i], 490989a36810SAnil Ravindranath pinstance->hrrq_start_bus_addr[i]); 491089a36810SAnil Ravindranath 491189a36810SAnil Ravindranath /* reset pointers and toggle bit to zeros */ 491289a36810SAnil Ravindranath pinstance->hrrq_start[i] = NULL; 491389a36810SAnil Ravindranath pinstance->hrrq_start_bus_addr[i] = 0; 491489a36810SAnil Ravindranath pinstance->host_toggle_bit[i] = 0; 491589a36810SAnil Ravindranath } 491689a36810SAnil Ravindranath } 491789a36810SAnil Ravindranath 491889a36810SAnil Ravindranath /** 491989a36810SAnil Ravindranath * pmcraid_allocate_host_rrqs - Allocate and initialize host RRQ buffers 492089a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 492189a36810SAnil Ravindranath * 492289a36810SAnil Ravindranath * Return value 492389a36810SAnil Ravindranath * 0 hrrq buffers are allocated, -ENOMEM otherwise. 492489a36810SAnil Ravindranath */ 492589a36810SAnil Ravindranath static int __devinit 492689a36810SAnil Ravindranath pmcraid_allocate_host_rrqs(struct pmcraid_instance *pinstance) 492789a36810SAnil Ravindranath { 4928c20c4267SAnil Ravindranath int i, buffer_size; 4929c20c4267SAnil Ravindranath 4930c20c4267SAnil Ravindranath buffer_size = HRRQ_ENTRY_SIZE * PMCRAID_MAX_CMD; 493189a36810SAnil Ravindranath 493289a36810SAnil Ravindranath for (i = 0; i < pinstance->num_hrrq; i++) { 493389a36810SAnil Ravindranath pinstance->hrrq_start[i] = 493489a36810SAnil Ravindranath pci_alloc_consistent( 493589a36810SAnil Ravindranath pinstance->pdev, 493689a36810SAnil Ravindranath buffer_size, 493789a36810SAnil Ravindranath &(pinstance->hrrq_start_bus_addr[i])); 493889a36810SAnil Ravindranath 493989a36810SAnil Ravindranath if (pinstance->hrrq_start[i] == 0) { 4940c20c4267SAnil Ravindranath pmcraid_err("pci_alloc failed for hrrq vector : %d\n", 4941c20c4267SAnil Ravindranath i); 494289a36810SAnil Ravindranath pmcraid_release_host_rrqs(pinstance, i); 494389a36810SAnil Ravindranath return -ENOMEM; 494489a36810SAnil Ravindranath } 494589a36810SAnil Ravindranath 494689a36810SAnil Ravindranath memset(pinstance->hrrq_start[i], 0, buffer_size); 494789a36810SAnil Ravindranath pinstance->hrrq_curr[i] = pinstance->hrrq_start[i]; 494889a36810SAnil Ravindranath pinstance->hrrq_end[i] = 4949c20c4267SAnil Ravindranath pinstance->hrrq_start[i] + PMCRAID_MAX_CMD - 1; 495089a36810SAnil Ravindranath pinstance->host_toggle_bit[i] = 1; 495189a36810SAnil Ravindranath spin_lock_init(&pinstance->hrrq_lock[i]); 495289a36810SAnil Ravindranath } 495389a36810SAnil Ravindranath return 0; 495489a36810SAnil Ravindranath } 495589a36810SAnil Ravindranath 495689a36810SAnil Ravindranath /** 495789a36810SAnil Ravindranath * pmcraid_release_hcams - release HCAM buffers 495889a36810SAnil Ravindranath * 495989a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 496089a36810SAnil Ravindranath * 496189a36810SAnil Ravindranath * Return value 496289a36810SAnil Ravindranath * none 496389a36810SAnil Ravindranath */ 496489a36810SAnil Ravindranath static void pmcraid_release_hcams(struct pmcraid_instance *pinstance) 496589a36810SAnil Ravindranath { 496689a36810SAnil Ravindranath if (pinstance->ccn.msg != NULL) { 496789a36810SAnil Ravindranath pci_free_consistent(pinstance->pdev, 496889a36810SAnil Ravindranath PMCRAID_AEN_HDR_SIZE + 4969c20c4267SAnil Ravindranath sizeof(struct pmcraid_hcam_ccn_ext), 497089a36810SAnil Ravindranath pinstance->ccn.msg, 497189a36810SAnil Ravindranath pinstance->ccn.baddr); 497289a36810SAnil Ravindranath 497389a36810SAnil Ravindranath pinstance->ccn.msg = NULL; 497489a36810SAnil Ravindranath pinstance->ccn.hcam = NULL; 497589a36810SAnil Ravindranath pinstance->ccn.baddr = 0; 497689a36810SAnil Ravindranath } 497789a36810SAnil Ravindranath 497889a36810SAnil Ravindranath if (pinstance->ldn.msg != NULL) { 497989a36810SAnil Ravindranath pci_free_consistent(pinstance->pdev, 498089a36810SAnil Ravindranath PMCRAID_AEN_HDR_SIZE + 498189a36810SAnil Ravindranath sizeof(struct pmcraid_hcam_ldn), 498289a36810SAnil Ravindranath pinstance->ldn.msg, 498389a36810SAnil Ravindranath pinstance->ldn.baddr); 498489a36810SAnil Ravindranath 498589a36810SAnil Ravindranath pinstance->ldn.msg = NULL; 498689a36810SAnil Ravindranath pinstance->ldn.hcam = NULL; 498789a36810SAnil Ravindranath pinstance->ldn.baddr = 0; 498889a36810SAnil Ravindranath } 498989a36810SAnil Ravindranath } 499089a36810SAnil Ravindranath 499189a36810SAnil Ravindranath /** 499289a36810SAnil Ravindranath * pmcraid_allocate_hcams - allocates HCAM buffers 499389a36810SAnil Ravindranath * @pinstance : pointer to per adapter instance structure 499489a36810SAnil Ravindranath * 499589a36810SAnil Ravindranath * Return Value: 499689a36810SAnil Ravindranath * 0 in case of successful allocation, non-zero otherwise 499789a36810SAnil Ravindranath */ 499889a36810SAnil Ravindranath static int pmcraid_allocate_hcams(struct pmcraid_instance *pinstance) 499989a36810SAnil Ravindranath { 500089a36810SAnil Ravindranath pinstance->ccn.msg = pci_alloc_consistent( 500189a36810SAnil Ravindranath pinstance->pdev, 500289a36810SAnil Ravindranath PMCRAID_AEN_HDR_SIZE + 5003c20c4267SAnil Ravindranath sizeof(struct pmcraid_hcam_ccn_ext), 500489a36810SAnil Ravindranath &(pinstance->ccn.baddr)); 500589a36810SAnil Ravindranath 500689a36810SAnil Ravindranath pinstance->ldn.msg = pci_alloc_consistent( 500789a36810SAnil Ravindranath pinstance->pdev, 500889a36810SAnil Ravindranath PMCRAID_AEN_HDR_SIZE + 500989a36810SAnil Ravindranath sizeof(struct pmcraid_hcam_ldn), 501089a36810SAnil Ravindranath &(pinstance->ldn.baddr)); 501189a36810SAnil Ravindranath 501289a36810SAnil Ravindranath if (pinstance->ldn.msg == NULL || pinstance->ccn.msg == NULL) { 501389a36810SAnil Ravindranath pmcraid_release_hcams(pinstance); 501489a36810SAnil Ravindranath } else { 501589a36810SAnil Ravindranath pinstance->ccn.hcam = 501689a36810SAnil Ravindranath (void *)pinstance->ccn.msg + PMCRAID_AEN_HDR_SIZE; 501789a36810SAnil Ravindranath pinstance->ldn.hcam = 501889a36810SAnil Ravindranath (void *)pinstance->ldn.msg + PMCRAID_AEN_HDR_SIZE; 501989a36810SAnil Ravindranath 502089a36810SAnil Ravindranath atomic_set(&pinstance->ccn.ignore, 0); 502189a36810SAnil Ravindranath atomic_set(&pinstance->ldn.ignore, 0); 502289a36810SAnil Ravindranath } 502389a36810SAnil Ravindranath 502489a36810SAnil Ravindranath return (pinstance->ldn.msg == NULL) ? -ENOMEM : 0; 502589a36810SAnil Ravindranath } 502689a36810SAnil Ravindranath 502789a36810SAnil Ravindranath /** 502889a36810SAnil Ravindranath * pmcraid_release_config_buffers - release config.table buffers 502989a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 503089a36810SAnil Ravindranath * 503189a36810SAnil Ravindranath * Return Value 503289a36810SAnil Ravindranath * none 503389a36810SAnil Ravindranath */ 503489a36810SAnil Ravindranath static void pmcraid_release_config_buffers(struct pmcraid_instance *pinstance) 503589a36810SAnil Ravindranath { 503689a36810SAnil Ravindranath if (pinstance->cfg_table != NULL && 503789a36810SAnil Ravindranath pinstance->cfg_table_bus_addr != 0) { 503889a36810SAnil Ravindranath pci_free_consistent(pinstance->pdev, 503989a36810SAnil Ravindranath sizeof(struct pmcraid_config_table), 504089a36810SAnil Ravindranath pinstance->cfg_table, 504189a36810SAnil Ravindranath pinstance->cfg_table_bus_addr); 504289a36810SAnil Ravindranath pinstance->cfg_table = NULL; 504389a36810SAnil Ravindranath pinstance->cfg_table_bus_addr = 0; 504489a36810SAnil Ravindranath } 504589a36810SAnil Ravindranath 504689a36810SAnil Ravindranath if (pinstance->res_entries != NULL) { 504789a36810SAnil Ravindranath int i; 504889a36810SAnil Ravindranath 504989a36810SAnil Ravindranath for (i = 0; i < PMCRAID_MAX_RESOURCES; i++) 505089a36810SAnil Ravindranath list_del(&pinstance->res_entries[i].queue); 505189a36810SAnil Ravindranath kfree(pinstance->res_entries); 505289a36810SAnil Ravindranath pinstance->res_entries = NULL; 505389a36810SAnil Ravindranath } 505489a36810SAnil Ravindranath 505589a36810SAnil Ravindranath pmcraid_release_hcams(pinstance); 505689a36810SAnil Ravindranath } 505789a36810SAnil Ravindranath 505889a36810SAnil Ravindranath /** 505989a36810SAnil Ravindranath * pmcraid_allocate_config_buffers - allocates DMAable memory for config table 506089a36810SAnil Ravindranath * @pinstance : pointer to per adapter instance structure 506189a36810SAnil Ravindranath * 506289a36810SAnil Ravindranath * Return Value 506389a36810SAnil Ravindranath * 0 for successful allocation, -ENOMEM for any failure 506489a36810SAnil Ravindranath */ 506589a36810SAnil Ravindranath static int __devinit 506689a36810SAnil Ravindranath pmcraid_allocate_config_buffers(struct pmcraid_instance *pinstance) 506789a36810SAnil Ravindranath { 506889a36810SAnil Ravindranath int i; 506989a36810SAnil Ravindranath 507089a36810SAnil Ravindranath pinstance->res_entries = 507189a36810SAnil Ravindranath kzalloc(sizeof(struct pmcraid_resource_entry) * 507289a36810SAnil Ravindranath PMCRAID_MAX_RESOURCES, GFP_KERNEL); 507389a36810SAnil Ravindranath 507489a36810SAnil Ravindranath if (NULL == pinstance->res_entries) { 507589a36810SAnil Ravindranath pmcraid_err("failed to allocate memory for resource table\n"); 507689a36810SAnil Ravindranath return -ENOMEM; 507789a36810SAnil Ravindranath } 507889a36810SAnil Ravindranath 507989a36810SAnil Ravindranath for (i = 0; i < PMCRAID_MAX_RESOURCES; i++) 508089a36810SAnil Ravindranath list_add_tail(&pinstance->res_entries[i].queue, 508189a36810SAnil Ravindranath &pinstance->free_res_q); 508289a36810SAnil Ravindranath 508389a36810SAnil Ravindranath pinstance->cfg_table = 508489a36810SAnil Ravindranath pci_alloc_consistent(pinstance->pdev, 508589a36810SAnil Ravindranath sizeof(struct pmcraid_config_table), 508689a36810SAnil Ravindranath &pinstance->cfg_table_bus_addr); 508789a36810SAnil Ravindranath 508889a36810SAnil Ravindranath if (NULL == pinstance->cfg_table) { 508989a36810SAnil Ravindranath pmcraid_err("couldn't alloc DMA memory for config table\n"); 509089a36810SAnil Ravindranath pmcraid_release_config_buffers(pinstance); 509189a36810SAnil Ravindranath return -ENOMEM; 509289a36810SAnil Ravindranath } 509389a36810SAnil Ravindranath 509489a36810SAnil Ravindranath if (pmcraid_allocate_hcams(pinstance)) { 509589a36810SAnil Ravindranath pmcraid_err("could not alloc DMA memory for HCAMS\n"); 509689a36810SAnil Ravindranath pmcraid_release_config_buffers(pinstance); 509789a36810SAnil Ravindranath return -ENOMEM; 509889a36810SAnil Ravindranath } 509989a36810SAnil Ravindranath 510089a36810SAnil Ravindranath return 0; 510189a36810SAnil Ravindranath } 510289a36810SAnil Ravindranath 510389a36810SAnil Ravindranath /** 510489a36810SAnil Ravindranath * pmcraid_init_tasklets - registers tasklets for response handling 510589a36810SAnil Ravindranath * 510689a36810SAnil Ravindranath * @pinstance: pointer adapter instance structure 510789a36810SAnil Ravindranath * 510889a36810SAnil Ravindranath * Return value 510989a36810SAnil Ravindranath * none 511089a36810SAnil Ravindranath */ 511189a36810SAnil Ravindranath static void pmcraid_init_tasklets(struct pmcraid_instance *pinstance) 511289a36810SAnil Ravindranath { 511389a36810SAnil Ravindranath int i; 511489a36810SAnil Ravindranath for (i = 0; i < pinstance->num_hrrq; i++) 511589a36810SAnil Ravindranath tasklet_init(&pinstance->isr_tasklet[i], 511689a36810SAnil Ravindranath pmcraid_tasklet_function, 511789a36810SAnil Ravindranath (unsigned long)&pinstance->hrrq_vector[i]); 511889a36810SAnil Ravindranath } 511989a36810SAnil Ravindranath 512089a36810SAnil Ravindranath /** 512189a36810SAnil Ravindranath * pmcraid_kill_tasklets - destroys tasklets registered for response handling 512289a36810SAnil Ravindranath * 512389a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 512489a36810SAnil Ravindranath * 512589a36810SAnil Ravindranath * Return value 512689a36810SAnil Ravindranath * none 512789a36810SAnil Ravindranath */ 512889a36810SAnil Ravindranath static void pmcraid_kill_tasklets(struct pmcraid_instance *pinstance) 512989a36810SAnil Ravindranath { 513089a36810SAnil Ravindranath int i; 513189a36810SAnil Ravindranath for (i = 0; i < pinstance->num_hrrq; i++) 513289a36810SAnil Ravindranath tasklet_kill(&pinstance->isr_tasklet[i]); 513389a36810SAnil Ravindranath } 513489a36810SAnil Ravindranath 513589a36810SAnil Ravindranath /** 5136c20c4267SAnil Ravindranath * pmcraid_release_buffers - release per-adapter buffers allocated 5137c20c4267SAnil Ravindranath * 5138c20c4267SAnil Ravindranath * @pinstance: pointer to adapter soft state 5139c20c4267SAnil Ravindranath * 5140c20c4267SAnil Ravindranath * Return Value 5141c20c4267SAnil Ravindranath * none 5142c20c4267SAnil Ravindranath */ 5143c20c4267SAnil Ravindranath static void pmcraid_release_buffers(struct pmcraid_instance *pinstance) 5144c20c4267SAnil Ravindranath { 5145c20c4267SAnil Ravindranath pmcraid_release_config_buffers(pinstance); 5146c20c4267SAnil Ravindranath pmcraid_release_control_blocks(pinstance, PMCRAID_MAX_CMD); 5147c20c4267SAnil Ravindranath pmcraid_release_cmd_blocks(pinstance, PMCRAID_MAX_CMD); 5148c20c4267SAnil Ravindranath pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); 5149c20c4267SAnil Ravindranath 5150c20c4267SAnil Ravindranath if (pinstance->inq_data != NULL) { 5151c20c4267SAnil Ravindranath pci_free_consistent(pinstance->pdev, 5152c20c4267SAnil Ravindranath sizeof(struct pmcraid_inquiry_data), 5153c20c4267SAnil Ravindranath pinstance->inq_data, 5154c20c4267SAnil Ravindranath pinstance->inq_data_baddr); 5155c20c4267SAnil Ravindranath 5156c20c4267SAnil Ravindranath pinstance->inq_data = NULL; 5157c20c4267SAnil Ravindranath pinstance->inq_data_baddr = 0; 5158c20c4267SAnil Ravindranath } 5159592488a3SAnil Ravindranath 5160592488a3SAnil Ravindranath if (pinstance->timestamp_data != NULL) { 5161592488a3SAnil Ravindranath pci_free_consistent(pinstance->pdev, 5162592488a3SAnil Ravindranath sizeof(struct pmcraid_timestamp_data), 5163592488a3SAnil Ravindranath pinstance->timestamp_data, 5164592488a3SAnil Ravindranath pinstance->timestamp_data_baddr); 5165592488a3SAnil Ravindranath 5166592488a3SAnil Ravindranath pinstance->timestamp_data = NULL; 5167592488a3SAnil Ravindranath pinstance->timestamp_data_baddr = 0; 5168592488a3SAnil Ravindranath } 5169c20c4267SAnil Ravindranath } 5170c20c4267SAnil Ravindranath 5171c20c4267SAnil Ravindranath /** 517289a36810SAnil Ravindranath * pmcraid_init_buffers - allocates memory and initializes various structures 517389a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 517489a36810SAnil Ravindranath * 517589a36810SAnil Ravindranath * This routine pre-allocates memory based on the type of block as below: 517689a36810SAnil Ravindranath * cmdblocks(PMCRAID_MAX_CMD): kernel memory using kernel's slab_allocator, 517789a36810SAnil Ravindranath * IOARCBs(PMCRAID_MAX_CMD) : DMAable memory, using pci pool allocator 517889a36810SAnil Ravindranath * config-table entries : DMAable memory using pci_alloc_consistent 517989a36810SAnil Ravindranath * HostRRQs : DMAable memory, using pci_alloc_consistent 518089a36810SAnil Ravindranath * 518189a36810SAnil Ravindranath * Return Value 518289a36810SAnil Ravindranath * 0 in case all of the blocks are allocated, -ENOMEM otherwise. 518389a36810SAnil Ravindranath */ 518489a36810SAnil Ravindranath static int __devinit pmcraid_init_buffers(struct pmcraid_instance *pinstance) 518589a36810SAnil Ravindranath { 518689a36810SAnil Ravindranath int i; 518789a36810SAnil Ravindranath 518889a36810SAnil Ravindranath if (pmcraid_allocate_host_rrqs(pinstance)) { 518989a36810SAnil Ravindranath pmcraid_err("couldn't allocate memory for %d host rrqs\n", 519089a36810SAnil Ravindranath pinstance->num_hrrq); 519189a36810SAnil Ravindranath return -ENOMEM; 519289a36810SAnil Ravindranath } 519389a36810SAnil Ravindranath 519489a36810SAnil Ravindranath if (pmcraid_allocate_config_buffers(pinstance)) { 519589a36810SAnil Ravindranath pmcraid_err("couldn't allocate memory for config buffers\n"); 519689a36810SAnil Ravindranath pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); 519789a36810SAnil Ravindranath return -ENOMEM; 519889a36810SAnil Ravindranath } 519989a36810SAnil Ravindranath 520089a36810SAnil Ravindranath if (pmcraid_allocate_cmd_blocks(pinstance)) { 520189a36810SAnil Ravindranath pmcraid_err("couldn't allocate memory for cmd blocks\n"); 520289a36810SAnil Ravindranath pmcraid_release_config_buffers(pinstance); 520389a36810SAnil Ravindranath pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); 520489a36810SAnil Ravindranath return -ENOMEM; 520589a36810SAnil Ravindranath } 520689a36810SAnil Ravindranath 520789a36810SAnil Ravindranath if (pmcraid_allocate_control_blocks(pinstance)) { 520889a36810SAnil Ravindranath pmcraid_err("couldn't allocate memory control blocks\n"); 520989a36810SAnil Ravindranath pmcraid_release_config_buffers(pinstance); 521089a36810SAnil Ravindranath pmcraid_release_cmd_blocks(pinstance, PMCRAID_MAX_CMD); 521189a36810SAnil Ravindranath pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); 521289a36810SAnil Ravindranath return -ENOMEM; 521389a36810SAnil Ravindranath } 521489a36810SAnil Ravindranath 5215c20c4267SAnil Ravindranath /* allocate DMAable memory for page D0 INQUIRY buffer */ 5216c20c4267SAnil Ravindranath pinstance->inq_data = pci_alloc_consistent( 5217c20c4267SAnil Ravindranath pinstance->pdev, 5218c20c4267SAnil Ravindranath sizeof(struct pmcraid_inquiry_data), 5219c20c4267SAnil Ravindranath &pinstance->inq_data_baddr); 5220c20c4267SAnil Ravindranath 5221c20c4267SAnil Ravindranath if (pinstance->inq_data == NULL) { 5222c20c4267SAnil Ravindranath pmcraid_err("couldn't allocate DMA memory for INQUIRY\n"); 5223c20c4267SAnil Ravindranath pmcraid_release_buffers(pinstance); 5224c20c4267SAnil Ravindranath return -ENOMEM; 5225c20c4267SAnil Ravindranath } 5226c20c4267SAnil Ravindranath 5227592488a3SAnil Ravindranath /* allocate DMAable memory for set timestamp data buffer */ 5228592488a3SAnil Ravindranath pinstance->timestamp_data = pci_alloc_consistent( 5229592488a3SAnil Ravindranath pinstance->pdev, 5230592488a3SAnil Ravindranath sizeof(struct pmcraid_timestamp_data), 5231592488a3SAnil Ravindranath &pinstance->timestamp_data_baddr); 5232592488a3SAnil Ravindranath 5233592488a3SAnil Ravindranath if (pinstance->timestamp_data == NULL) { 5234592488a3SAnil Ravindranath pmcraid_err("couldn't allocate DMA memory for \ 5235592488a3SAnil Ravindranath set time_stamp \n"); 5236592488a3SAnil Ravindranath pmcraid_release_buffers(pinstance); 5237592488a3SAnil Ravindranath return -ENOMEM; 5238592488a3SAnil Ravindranath } 5239592488a3SAnil Ravindranath 5240592488a3SAnil Ravindranath 524189a36810SAnil Ravindranath /* Initialize all the command blocks and add them to free pool. No 524289a36810SAnil Ravindranath * need to lock (free_pool_lock) as this is done in initialization 524389a36810SAnil Ravindranath * itself 524489a36810SAnil Ravindranath */ 524589a36810SAnil Ravindranath for (i = 0; i < PMCRAID_MAX_CMD; i++) { 524689a36810SAnil Ravindranath struct pmcraid_cmd *cmdp = pinstance->cmd_list[i]; 524789a36810SAnil Ravindranath pmcraid_init_cmdblk(cmdp, i); 524889a36810SAnil Ravindranath cmdp->drv_inst = pinstance; 524989a36810SAnil Ravindranath list_add_tail(&cmdp->free_list, &pinstance->free_cmd_pool); 525089a36810SAnil Ravindranath } 525189a36810SAnil Ravindranath 525289a36810SAnil Ravindranath return 0; 525389a36810SAnil Ravindranath } 525489a36810SAnil Ravindranath 525589a36810SAnil Ravindranath /** 525689a36810SAnil Ravindranath * pmcraid_reinit_buffers - resets various buffer pointers 525789a36810SAnil Ravindranath * @pinstance: pointer to adapter instance 525889a36810SAnil Ravindranath * Return value 525989a36810SAnil Ravindranath * none 526089a36810SAnil Ravindranath */ 526189a36810SAnil Ravindranath static void pmcraid_reinit_buffers(struct pmcraid_instance *pinstance) 526289a36810SAnil Ravindranath { 526389a36810SAnil Ravindranath int i; 526489a36810SAnil Ravindranath int buffer_size = HRRQ_ENTRY_SIZE * PMCRAID_MAX_CMD; 526589a36810SAnil Ravindranath 526689a36810SAnil Ravindranath for (i = 0; i < pinstance->num_hrrq; i++) { 526789a36810SAnil Ravindranath memset(pinstance->hrrq_start[i], 0, buffer_size); 526889a36810SAnil Ravindranath pinstance->hrrq_curr[i] = pinstance->hrrq_start[i]; 526989a36810SAnil Ravindranath pinstance->hrrq_end[i] = 527089a36810SAnil Ravindranath pinstance->hrrq_start[i] + PMCRAID_MAX_CMD - 1; 527189a36810SAnil Ravindranath pinstance->host_toggle_bit[i] = 1; 527289a36810SAnil Ravindranath } 527389a36810SAnil Ravindranath } 527489a36810SAnil Ravindranath 527589a36810SAnil Ravindranath /** 527689a36810SAnil Ravindranath * pmcraid_init_instance - initialize per instance data structure 527789a36810SAnil Ravindranath * @pdev: pointer to pci device structure 527889a36810SAnil Ravindranath * @host: pointer to Scsi_Host structure 527989a36810SAnil Ravindranath * @mapped_pci_addr: memory mapped IOA configuration registers 528089a36810SAnil Ravindranath * 528189a36810SAnil Ravindranath * Return Value 528289a36810SAnil Ravindranath * 0 on success, non-zero in case of any failure 528389a36810SAnil Ravindranath */ 528489a36810SAnil Ravindranath static int __devinit pmcraid_init_instance( 528589a36810SAnil Ravindranath struct pci_dev *pdev, 528689a36810SAnil Ravindranath struct Scsi_Host *host, 528789a36810SAnil Ravindranath void __iomem *mapped_pci_addr 528889a36810SAnil Ravindranath ) 528989a36810SAnil Ravindranath { 529089a36810SAnil Ravindranath struct pmcraid_instance *pinstance = 529189a36810SAnil Ravindranath (struct pmcraid_instance *)host->hostdata; 529289a36810SAnil Ravindranath 529389a36810SAnil Ravindranath pinstance->host = host; 529489a36810SAnil Ravindranath pinstance->pdev = pdev; 529589a36810SAnil Ravindranath 529689a36810SAnil Ravindranath /* Initialize register addresses */ 529789a36810SAnil Ravindranath pinstance->mapped_dma_addr = mapped_pci_addr; 529889a36810SAnil Ravindranath 529989a36810SAnil Ravindranath /* Initialize chip-specific details */ 530089a36810SAnil Ravindranath { 530189a36810SAnil Ravindranath struct pmcraid_chip_details *chip_cfg = pinstance->chip_cfg; 530289a36810SAnil Ravindranath struct pmcraid_interrupts *pint_regs = &pinstance->int_regs; 530389a36810SAnil Ravindranath 530489a36810SAnil Ravindranath pinstance->ioarrin = mapped_pci_addr + chip_cfg->ioarrin; 530589a36810SAnil Ravindranath 530689a36810SAnil Ravindranath pint_regs->ioa_host_interrupt_reg = 530789a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->ioa_host_intr; 530889a36810SAnil Ravindranath pint_regs->ioa_host_interrupt_clr_reg = 530989a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->ioa_host_intr_clr; 5310c20c4267SAnil Ravindranath pint_regs->ioa_host_msix_interrupt_reg = 5311c20c4267SAnil Ravindranath mapped_pci_addr + chip_cfg->ioa_host_msix_intr; 531289a36810SAnil Ravindranath pint_regs->host_ioa_interrupt_reg = 531389a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->host_ioa_intr; 531489a36810SAnil Ravindranath pint_regs->host_ioa_interrupt_clr_reg = 531589a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->host_ioa_intr_clr; 531689a36810SAnil Ravindranath 531789a36810SAnil Ravindranath /* Current version of firmware exposes interrupt mask set 531889a36810SAnil Ravindranath * and mask clr registers through memory mapped bar0. 531989a36810SAnil Ravindranath */ 532089a36810SAnil Ravindranath pinstance->mailbox = mapped_pci_addr + chip_cfg->mailbox; 532189a36810SAnil Ravindranath pinstance->ioa_status = mapped_pci_addr + chip_cfg->ioastatus; 532289a36810SAnil Ravindranath pint_regs->ioa_host_interrupt_mask_reg = 532389a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->ioa_host_mask; 532489a36810SAnil Ravindranath pint_regs->ioa_host_interrupt_mask_clr_reg = 532589a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->ioa_host_mask_clr; 532689a36810SAnil Ravindranath pint_regs->global_interrupt_mask_reg = 532789a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->global_intr_mask; 532889a36810SAnil Ravindranath }; 532989a36810SAnil Ravindranath 533089a36810SAnil Ravindranath pinstance->ioa_reset_attempts = 0; 533189a36810SAnil Ravindranath init_waitqueue_head(&pinstance->reset_wait_q); 533289a36810SAnil Ravindranath 533389a36810SAnil Ravindranath atomic_set(&pinstance->outstanding_cmds, 0); 5334c20c4267SAnil Ravindranath atomic_set(&pinstance->last_message_id, 0); 533589a36810SAnil Ravindranath atomic_set(&pinstance->expose_resources, 0); 533689a36810SAnil Ravindranath 533789a36810SAnil Ravindranath INIT_LIST_HEAD(&pinstance->free_res_q); 533889a36810SAnil Ravindranath INIT_LIST_HEAD(&pinstance->used_res_q); 533989a36810SAnil Ravindranath INIT_LIST_HEAD(&pinstance->free_cmd_pool); 534089a36810SAnil Ravindranath INIT_LIST_HEAD(&pinstance->pending_cmd_pool); 534189a36810SAnil Ravindranath 534289a36810SAnil Ravindranath spin_lock_init(&pinstance->free_pool_lock); 534389a36810SAnil Ravindranath spin_lock_init(&pinstance->pending_pool_lock); 534489a36810SAnil Ravindranath spin_lock_init(&pinstance->resource_lock); 534589a36810SAnil Ravindranath mutex_init(&pinstance->aen_queue_lock); 534689a36810SAnil Ravindranath 534789a36810SAnil Ravindranath /* Work-queue (Shared) for deferred processing error handling */ 534889a36810SAnil Ravindranath INIT_WORK(&pinstance->worker_q, pmcraid_worker_function); 534989a36810SAnil Ravindranath 535089a36810SAnil Ravindranath /* Initialize the default log_level */ 535189a36810SAnil Ravindranath pinstance->current_log_level = pmcraid_log_level; 535289a36810SAnil Ravindranath 535389a36810SAnil Ravindranath /* Setup variables required for reset engine */ 535489a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_UNKNOWN; 535589a36810SAnil Ravindranath pinstance->reset_cmd = NULL; 535689a36810SAnil Ravindranath return 0; 535789a36810SAnil Ravindranath } 535889a36810SAnil Ravindranath 535989a36810SAnil Ravindranath /** 536089a36810SAnil Ravindranath * pmcraid_shutdown - shutdown adapter controller. 536189a36810SAnil Ravindranath * @pdev: pci device struct 536289a36810SAnil Ravindranath * 536389a36810SAnil Ravindranath * Issues an adapter shutdown to the card waits for its completion 536489a36810SAnil Ravindranath * 536589a36810SAnil Ravindranath * Return value 536689a36810SAnil Ravindranath * none 536789a36810SAnil Ravindranath */ 536889a36810SAnil Ravindranath static void pmcraid_shutdown(struct pci_dev *pdev) 536989a36810SAnil Ravindranath { 537089a36810SAnil Ravindranath struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); 537189a36810SAnil Ravindranath pmcraid_reset_bringdown(pinstance); 537289a36810SAnil Ravindranath } 537389a36810SAnil Ravindranath 537489a36810SAnil Ravindranath 537589a36810SAnil Ravindranath /** 537689a36810SAnil Ravindranath * pmcraid_get_minor - returns unused minor number from minor number bitmap 537789a36810SAnil Ravindranath */ 537889a36810SAnil Ravindranath static unsigned short pmcraid_get_minor(void) 537989a36810SAnil Ravindranath { 538089a36810SAnil Ravindranath int minor; 538189a36810SAnil Ravindranath 538289a36810SAnil Ravindranath minor = find_first_zero_bit(pmcraid_minor, sizeof(pmcraid_minor)); 538389a36810SAnil Ravindranath __set_bit(minor, pmcraid_minor); 538489a36810SAnil Ravindranath return minor; 538589a36810SAnil Ravindranath } 538689a36810SAnil Ravindranath 538789a36810SAnil Ravindranath /** 538889a36810SAnil Ravindranath * pmcraid_release_minor - releases given minor back to minor number bitmap 538989a36810SAnil Ravindranath */ 539089a36810SAnil Ravindranath static void pmcraid_release_minor(unsigned short minor) 539189a36810SAnil Ravindranath { 539289a36810SAnil Ravindranath __clear_bit(minor, pmcraid_minor); 539389a36810SAnil Ravindranath } 539489a36810SAnil Ravindranath 539589a36810SAnil Ravindranath /** 539689a36810SAnil Ravindranath * pmcraid_setup_chrdev - allocates a minor number and registers a char device 539789a36810SAnil Ravindranath * 539889a36810SAnil Ravindranath * @pinstance: pointer to adapter instance for which to register device 539989a36810SAnil Ravindranath * 540089a36810SAnil Ravindranath * Return value 540189a36810SAnil Ravindranath * 0 in case of success, otherwise non-zero 540289a36810SAnil Ravindranath */ 540389a36810SAnil Ravindranath static int pmcraid_setup_chrdev(struct pmcraid_instance *pinstance) 540489a36810SAnil Ravindranath { 540589a36810SAnil Ravindranath int minor; 540689a36810SAnil Ravindranath int error; 540789a36810SAnil Ravindranath 540889a36810SAnil Ravindranath minor = pmcraid_get_minor(); 540989a36810SAnil Ravindranath cdev_init(&pinstance->cdev, &pmcraid_fops); 541089a36810SAnil Ravindranath pinstance->cdev.owner = THIS_MODULE; 541189a36810SAnil Ravindranath 541289a36810SAnil Ravindranath error = cdev_add(&pinstance->cdev, MKDEV(pmcraid_major, minor), 1); 541389a36810SAnil Ravindranath 541489a36810SAnil Ravindranath if (error) 541589a36810SAnil Ravindranath pmcraid_release_minor(minor); 541689a36810SAnil Ravindranath else 541789a36810SAnil Ravindranath device_create(pmcraid_class, NULL, MKDEV(pmcraid_major, minor), 5418c20c4267SAnil Ravindranath NULL, "%s%u", PMCRAID_DEVFILE, minor); 541989a36810SAnil Ravindranath return error; 542089a36810SAnil Ravindranath } 542189a36810SAnil Ravindranath 542289a36810SAnil Ravindranath /** 542389a36810SAnil Ravindranath * pmcraid_release_chrdev - unregisters per-adapter management interface 542489a36810SAnil Ravindranath * 542589a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 542689a36810SAnil Ravindranath * 542789a36810SAnil Ravindranath * Return value 542889a36810SAnil Ravindranath * none 542989a36810SAnil Ravindranath */ 543089a36810SAnil Ravindranath static void pmcraid_release_chrdev(struct pmcraid_instance *pinstance) 543189a36810SAnil Ravindranath { 543289a36810SAnil Ravindranath pmcraid_release_minor(MINOR(pinstance->cdev.dev)); 543389a36810SAnil Ravindranath device_destroy(pmcraid_class, 543489a36810SAnil Ravindranath MKDEV(pmcraid_major, MINOR(pinstance->cdev.dev))); 543589a36810SAnil Ravindranath cdev_del(&pinstance->cdev); 543689a36810SAnil Ravindranath } 543789a36810SAnil Ravindranath 543889a36810SAnil Ravindranath /** 543989a36810SAnil Ravindranath * pmcraid_remove - IOA hot plug remove entry point 544089a36810SAnil Ravindranath * @pdev: pci device struct 544189a36810SAnil Ravindranath * 544289a36810SAnil Ravindranath * Return value 544389a36810SAnil Ravindranath * none 544489a36810SAnil Ravindranath */ 544589a36810SAnil Ravindranath static void __devexit pmcraid_remove(struct pci_dev *pdev) 544689a36810SAnil Ravindranath { 544789a36810SAnil Ravindranath struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); 544889a36810SAnil Ravindranath 544989a36810SAnil Ravindranath /* remove the management interface (/dev file) for this device */ 545089a36810SAnil Ravindranath pmcraid_release_chrdev(pinstance); 545189a36810SAnil Ravindranath 545289a36810SAnil Ravindranath /* remove host template from scsi midlayer */ 545389a36810SAnil Ravindranath scsi_remove_host(pinstance->host); 545489a36810SAnil Ravindranath 545589a36810SAnil Ravindranath /* block requests from mid-layer */ 545689a36810SAnil Ravindranath scsi_block_requests(pinstance->host); 545789a36810SAnil Ravindranath 545889a36810SAnil Ravindranath /* initiate shutdown adapter */ 545989a36810SAnil Ravindranath pmcraid_shutdown(pdev); 546089a36810SAnil Ravindranath 546189a36810SAnil Ravindranath pmcraid_disable_interrupts(pinstance, ~0); 546243829731STejun Heo flush_work(&pinstance->worker_q); 546389a36810SAnil Ravindranath 546489a36810SAnil Ravindranath pmcraid_kill_tasklets(pinstance); 546589a36810SAnil Ravindranath pmcraid_unregister_interrupt_handler(pinstance); 546689a36810SAnil Ravindranath pmcraid_release_buffers(pinstance); 546789a36810SAnil Ravindranath iounmap(pinstance->mapped_dma_addr); 546889a36810SAnil Ravindranath pci_release_regions(pdev); 546989a36810SAnil Ravindranath scsi_host_put(pinstance->host); 547089a36810SAnil Ravindranath pci_disable_device(pdev); 547189a36810SAnil Ravindranath 547289a36810SAnil Ravindranath return; 547389a36810SAnil Ravindranath } 547489a36810SAnil Ravindranath 547589a36810SAnil Ravindranath #ifdef CONFIG_PM 547689a36810SAnil Ravindranath /** 547789a36810SAnil Ravindranath * pmcraid_suspend - driver suspend entry point for power management 547889a36810SAnil Ravindranath * @pdev: PCI device structure 547989a36810SAnil Ravindranath * @state: PCI power state to suspend routine 548089a36810SAnil Ravindranath * 548189a36810SAnil Ravindranath * Return Value - 0 always 548289a36810SAnil Ravindranath */ 548389a36810SAnil Ravindranath static int pmcraid_suspend(struct pci_dev *pdev, pm_message_t state) 548489a36810SAnil Ravindranath { 548589a36810SAnil Ravindranath struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); 548689a36810SAnil Ravindranath 548789a36810SAnil Ravindranath pmcraid_shutdown(pdev); 548889a36810SAnil Ravindranath pmcraid_disable_interrupts(pinstance, ~0); 548989a36810SAnil Ravindranath pmcraid_kill_tasklets(pinstance); 549089a36810SAnil Ravindranath pci_set_drvdata(pinstance->pdev, pinstance); 549189a36810SAnil Ravindranath pmcraid_unregister_interrupt_handler(pinstance); 549289a36810SAnil Ravindranath pci_save_state(pdev); 549389a36810SAnil Ravindranath pci_disable_device(pdev); 549489a36810SAnil Ravindranath pci_set_power_state(pdev, pci_choose_state(pdev, state)); 549589a36810SAnil Ravindranath 549689a36810SAnil Ravindranath return 0; 549789a36810SAnil Ravindranath } 549889a36810SAnil Ravindranath 549989a36810SAnil Ravindranath /** 550089a36810SAnil Ravindranath * pmcraid_resume - driver resume entry point PCI power management 550189a36810SAnil Ravindranath * @pdev: PCI device structure 550289a36810SAnil Ravindranath * 550389a36810SAnil Ravindranath * Return Value - 0 in case of success. Error code in case of any failure 550489a36810SAnil Ravindranath */ 550589a36810SAnil Ravindranath static int pmcraid_resume(struct pci_dev *pdev) 550689a36810SAnil Ravindranath { 550789a36810SAnil Ravindranath struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); 550889a36810SAnil Ravindranath struct Scsi_Host *host = pinstance->host; 550989a36810SAnil Ravindranath int rc; 551089a36810SAnil Ravindranath 551189a36810SAnil Ravindranath pci_set_power_state(pdev, PCI_D0); 551289a36810SAnil Ravindranath pci_enable_wake(pdev, PCI_D0, 0); 551389a36810SAnil Ravindranath pci_restore_state(pdev); 551489a36810SAnil Ravindranath 551589a36810SAnil Ravindranath rc = pci_enable_device(pdev); 551689a36810SAnil Ravindranath 551789a36810SAnil Ravindranath if (rc) { 551834876402SAnil Ravindranath dev_err(&pdev->dev, "resume: Enable device failed\n"); 551989a36810SAnil Ravindranath return rc; 552089a36810SAnil Ravindranath } 552189a36810SAnil Ravindranath 552289a36810SAnil Ravindranath pci_set_master(pdev); 552389a36810SAnil Ravindranath 552489a36810SAnil Ravindranath if ((sizeof(dma_addr_t) == 4) || 552589a36810SAnil Ravindranath pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) 552689a36810SAnil Ravindranath rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 552789a36810SAnil Ravindranath 552889a36810SAnil Ravindranath if (rc == 0) 552989a36810SAnil Ravindranath rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); 553089a36810SAnil Ravindranath 553189a36810SAnil Ravindranath if (rc != 0) { 553234876402SAnil Ravindranath dev_err(&pdev->dev, "resume: Failed to set PCI DMA mask\n"); 553389a36810SAnil Ravindranath goto disable_device; 553489a36810SAnil Ravindranath } 553589a36810SAnil Ravindranath 5536c20c4267SAnil Ravindranath pmcraid_disable_interrupts(pinstance, ~0); 553789a36810SAnil Ravindranath atomic_set(&pinstance->outstanding_cmds, 0); 553889a36810SAnil Ravindranath rc = pmcraid_register_interrupt_handler(pinstance); 553989a36810SAnil Ravindranath 554089a36810SAnil Ravindranath if (rc) { 554134876402SAnil Ravindranath dev_err(&pdev->dev, 554234876402SAnil Ravindranath "resume: couldn't register interrupt handlers\n"); 554389a36810SAnil Ravindranath rc = -ENODEV; 554489a36810SAnil Ravindranath goto release_host; 554589a36810SAnil Ravindranath } 554689a36810SAnil Ravindranath 554789a36810SAnil Ravindranath pmcraid_init_tasklets(pinstance); 554889a36810SAnil Ravindranath pmcraid_enable_interrupts(pinstance, PMCRAID_PCI_INTERRUPTS); 554989a36810SAnil Ravindranath 555089a36810SAnil Ravindranath /* Start with hard reset sequence which brings up IOA to operational 555189a36810SAnil Ravindranath * state as well as completes the reset sequence. 555289a36810SAnil Ravindranath */ 555389a36810SAnil Ravindranath pinstance->ioa_hard_reset = 1; 555489a36810SAnil Ravindranath 555589a36810SAnil Ravindranath /* Start IOA firmware initialization and bring card to Operational 555689a36810SAnil Ravindranath * state. 555789a36810SAnil Ravindranath */ 555889a36810SAnil Ravindranath if (pmcraid_reset_bringup(pinstance)) { 555934876402SAnil Ravindranath dev_err(&pdev->dev, "couldn't initialize IOA\n"); 556089a36810SAnil Ravindranath rc = -ENODEV; 556189a36810SAnil Ravindranath goto release_tasklets; 556289a36810SAnil Ravindranath } 556389a36810SAnil Ravindranath 556489a36810SAnil Ravindranath return 0; 556589a36810SAnil Ravindranath 556689a36810SAnil Ravindranath release_tasklets: 5567c20c4267SAnil Ravindranath pmcraid_disable_interrupts(pinstance, ~0); 556889a36810SAnil Ravindranath pmcraid_kill_tasklets(pinstance); 556989a36810SAnil Ravindranath pmcraid_unregister_interrupt_handler(pinstance); 557089a36810SAnil Ravindranath 557189a36810SAnil Ravindranath release_host: 557289a36810SAnil Ravindranath scsi_host_put(host); 557389a36810SAnil Ravindranath 557489a36810SAnil Ravindranath disable_device: 557589a36810SAnil Ravindranath pci_disable_device(pdev); 557689a36810SAnil Ravindranath 557789a36810SAnil Ravindranath return rc; 557889a36810SAnil Ravindranath } 557989a36810SAnil Ravindranath 558089a36810SAnil Ravindranath #else 558189a36810SAnil Ravindranath 558289a36810SAnil Ravindranath #define pmcraid_suspend NULL 558389a36810SAnil Ravindranath #define pmcraid_resume NULL 558489a36810SAnil Ravindranath 558589a36810SAnil Ravindranath #endif /* CONFIG_PM */ 558689a36810SAnil Ravindranath 558789a36810SAnil Ravindranath /** 558889a36810SAnil Ravindranath * pmcraid_complete_ioa_reset - Called by either timer or tasklet during 558989a36810SAnil Ravindranath * completion of the ioa reset 559089a36810SAnil Ravindranath * @cmd: pointer to reset command block 559189a36810SAnil Ravindranath */ 559289a36810SAnil Ravindranath static void pmcraid_complete_ioa_reset(struct pmcraid_cmd *cmd) 559389a36810SAnil Ravindranath { 559489a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 559589a36810SAnil Ravindranath unsigned long flags; 559689a36810SAnil Ravindranath 559789a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, flags); 559889a36810SAnil Ravindranath pmcraid_ioa_reset(cmd); 559989a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, flags); 560089a36810SAnil Ravindranath scsi_unblock_requests(pinstance->host); 560189a36810SAnil Ravindranath schedule_work(&pinstance->worker_q); 560289a36810SAnil Ravindranath } 560389a36810SAnil Ravindranath 560489a36810SAnil Ravindranath /** 560589a36810SAnil Ravindranath * pmcraid_set_supported_devs - sends SET SUPPORTED DEVICES to IOAFP 560689a36810SAnil Ravindranath * 560789a36810SAnil Ravindranath * @cmd: pointer to pmcraid_cmd structure 560889a36810SAnil Ravindranath * 560989a36810SAnil Ravindranath * Return Value 561089a36810SAnil Ravindranath * 0 for success or non-zero for failure cases 561189a36810SAnil Ravindranath */ 561289a36810SAnil Ravindranath static void pmcraid_set_supported_devs(struct pmcraid_cmd *cmd) 561389a36810SAnil Ravindranath { 561489a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 561589a36810SAnil Ravindranath void (*cmd_done) (struct pmcraid_cmd *) = pmcraid_complete_ioa_reset; 561689a36810SAnil Ravindranath 561789a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 561889a36810SAnil Ravindranath 561989a36810SAnil Ravindranath ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); 562089a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_IOACMD; 562189a36810SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_SET_SUPPORTED_DEVICES; 562289a36810SAnil Ravindranath ioarcb->cdb[1] = ALL_DEVICES_SUPPORTED; 562389a36810SAnil Ravindranath 562489a36810SAnil Ravindranath /* If this was called as part of resource table reinitialization due to 562589a36810SAnil Ravindranath * lost CCN, it is enough to return the command block back to free pool 562689a36810SAnil Ravindranath * as part of set_supported_devs completion function. 562789a36810SAnil Ravindranath */ 562889a36810SAnil Ravindranath if (cmd->drv_inst->reinit_cfg_table) { 562989a36810SAnil Ravindranath cmd->drv_inst->reinit_cfg_table = 0; 563089a36810SAnil Ravindranath cmd->release = 1; 563189a36810SAnil Ravindranath cmd_done = pmcraid_reinit_cfgtable_done; 563289a36810SAnil Ravindranath } 563389a36810SAnil Ravindranath 563489a36810SAnil Ravindranath /* we will be done with the reset sequence after set supported devices, 563589a36810SAnil Ravindranath * setup the done function to return the command block back to free 563689a36810SAnil Ravindranath * pool 563789a36810SAnil Ravindranath */ 563889a36810SAnil Ravindranath pmcraid_send_cmd(cmd, 563989a36810SAnil Ravindranath cmd_done, 564089a36810SAnil Ravindranath PMCRAID_SET_SUP_DEV_TIMEOUT, 564189a36810SAnil Ravindranath pmcraid_timeout_handler); 564289a36810SAnil Ravindranath return; 564389a36810SAnil Ravindranath } 564489a36810SAnil Ravindranath 564589a36810SAnil Ravindranath /** 5646592488a3SAnil Ravindranath * pmcraid_set_timestamp - set the timestamp to IOAFP 5647592488a3SAnil Ravindranath * 5648592488a3SAnil Ravindranath * @cmd: pointer to pmcraid_cmd structure 5649592488a3SAnil Ravindranath * 5650592488a3SAnil Ravindranath * Return Value 5651592488a3SAnil Ravindranath * 0 for success or non-zero for failure cases 5652592488a3SAnil Ravindranath */ 5653592488a3SAnil Ravindranath static void pmcraid_set_timestamp(struct pmcraid_cmd *cmd) 5654592488a3SAnil Ravindranath { 5655592488a3SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 5656592488a3SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 5657592488a3SAnil Ravindranath __be32 time_stamp_len = cpu_to_be32(PMCRAID_TIMESTAMP_LEN); 5658592488a3SAnil Ravindranath struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; 5659592488a3SAnil Ravindranath 5660592488a3SAnil Ravindranath struct timeval tv; 5661592488a3SAnil Ravindranath __le64 timestamp; 5662592488a3SAnil Ravindranath 5663592488a3SAnil Ravindranath do_gettimeofday(&tv); 5664592488a3SAnil Ravindranath timestamp = tv.tv_sec * 1000; 5665592488a3SAnil Ravindranath 5666592488a3SAnil Ravindranath pinstance->timestamp_data->timestamp[0] = (__u8)(timestamp); 5667592488a3SAnil Ravindranath pinstance->timestamp_data->timestamp[1] = (__u8)((timestamp) >> 8); 5668592488a3SAnil Ravindranath pinstance->timestamp_data->timestamp[2] = (__u8)((timestamp) >> 16); 5669592488a3SAnil Ravindranath pinstance->timestamp_data->timestamp[3] = (__u8)((timestamp) >> 24); 5670592488a3SAnil Ravindranath pinstance->timestamp_data->timestamp[4] = (__u8)((timestamp) >> 32); 5671592488a3SAnil Ravindranath pinstance->timestamp_data->timestamp[5] = (__u8)((timestamp) >> 40); 5672592488a3SAnil Ravindranath 5673592488a3SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 5674592488a3SAnil Ravindranath ioarcb->request_type = REQ_TYPE_SCSI; 5675592488a3SAnil Ravindranath ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); 5676592488a3SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_SCSI_SET_TIMESTAMP; 5677592488a3SAnil Ravindranath ioarcb->cdb[1] = PMCRAID_SCSI_SERVICE_ACTION; 5678592488a3SAnil Ravindranath memcpy(&(ioarcb->cdb[6]), &time_stamp_len, sizeof(time_stamp_len)); 5679592488a3SAnil Ravindranath 5680592488a3SAnil Ravindranath ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + 5681592488a3SAnil Ravindranath offsetof(struct pmcraid_ioarcb, 5682592488a3SAnil Ravindranath add_data.u.ioadl[0])); 5683592488a3SAnil Ravindranath ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); 5684592488a3SAnil Ravindranath ioarcb->ioarcb_bus_addr &= ~(0x1FULL); 5685592488a3SAnil Ravindranath 5686592488a3SAnil Ravindranath ioarcb->request_flags0 |= NO_LINK_DESCS; 5687592488a3SAnil Ravindranath ioarcb->request_flags0 |= TRANSFER_DIR_WRITE; 5688592488a3SAnil Ravindranath ioarcb->data_transfer_length = 5689592488a3SAnil Ravindranath cpu_to_le32(sizeof(struct pmcraid_timestamp_data)); 5690592488a3SAnil Ravindranath ioadl = &(ioarcb->add_data.u.ioadl[0]); 5691592488a3SAnil Ravindranath ioadl->flags = IOADL_FLAGS_LAST_DESC; 5692592488a3SAnil Ravindranath ioadl->address = cpu_to_le64(pinstance->timestamp_data_baddr); 5693592488a3SAnil Ravindranath ioadl->data_len = cpu_to_le32(sizeof(struct pmcraid_timestamp_data)); 5694592488a3SAnil Ravindranath 5695592488a3SAnil Ravindranath if (!pinstance->timestamp_error) { 5696592488a3SAnil Ravindranath pinstance->timestamp_error = 0; 5697592488a3SAnil Ravindranath pmcraid_send_cmd(cmd, pmcraid_set_supported_devs, 5698592488a3SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler); 5699592488a3SAnil Ravindranath } else { 5700592488a3SAnil Ravindranath pmcraid_send_cmd(cmd, pmcraid_return_cmd, 5701592488a3SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler); 5702592488a3SAnil Ravindranath return; 5703592488a3SAnil Ravindranath } 5704592488a3SAnil Ravindranath } 5705592488a3SAnil Ravindranath 5706592488a3SAnil Ravindranath 5707592488a3SAnil Ravindranath /** 570889a36810SAnil Ravindranath * pmcraid_init_res_table - Initialize the resource table 570989a36810SAnil Ravindranath * @cmd: pointer to pmcraid command struct 571089a36810SAnil Ravindranath * 571189a36810SAnil Ravindranath * This function looks through the existing resource table, comparing 571289a36810SAnil Ravindranath * it with the config table. This function will take care of old/new 571389a36810SAnil Ravindranath * devices and schedule adding/removing them from the mid-layer 571489a36810SAnil Ravindranath * as appropriate. 571589a36810SAnil Ravindranath * 571689a36810SAnil Ravindranath * Return value 571789a36810SAnil Ravindranath * None 571889a36810SAnil Ravindranath */ 571989a36810SAnil Ravindranath static void pmcraid_init_res_table(struct pmcraid_cmd *cmd) 572089a36810SAnil Ravindranath { 572189a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 572289a36810SAnil Ravindranath struct pmcraid_resource_entry *res, *temp; 572389a36810SAnil Ravindranath struct pmcraid_config_table_entry *cfgte; 572489a36810SAnil Ravindranath unsigned long lock_flags; 572589a36810SAnil Ravindranath int found, rc, i; 5726c20c4267SAnil Ravindranath u16 fw_version; 572789a36810SAnil Ravindranath LIST_HEAD(old_res); 572889a36810SAnil Ravindranath 572989a36810SAnil Ravindranath if (pinstance->cfg_table->flags & MICROCODE_UPDATE_REQUIRED) 573034876402SAnil Ravindranath pmcraid_err("IOA requires microcode download\n"); 573189a36810SAnil Ravindranath 5732c20c4267SAnil Ravindranath fw_version = be16_to_cpu(pinstance->inq_data->fw_version); 5733c20c4267SAnil Ravindranath 573489a36810SAnil Ravindranath /* resource list is protected by pinstance->resource_lock. 573589a36810SAnil Ravindranath * init_res_table can be called from probe (user-thread) or runtime 573689a36810SAnil Ravindranath * reset (timer/tasklet) 573789a36810SAnil Ravindranath */ 573889a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->resource_lock, lock_flags); 573989a36810SAnil Ravindranath 574089a36810SAnil Ravindranath list_for_each_entry_safe(res, temp, &pinstance->used_res_q, queue) 574189a36810SAnil Ravindranath list_move_tail(&res->queue, &old_res); 574289a36810SAnil Ravindranath 574389a36810SAnil Ravindranath for (i = 0; i < pinstance->cfg_table->num_entries; i++) { 5744c20c4267SAnil Ravindranath if (be16_to_cpu(pinstance->inq_data->fw_version) <= 5745c20c4267SAnil Ravindranath PMCRAID_FW_VERSION_1) 574689a36810SAnil Ravindranath cfgte = &pinstance->cfg_table->entries[i]; 5747c20c4267SAnil Ravindranath else 5748c20c4267SAnil Ravindranath cfgte = (struct pmcraid_config_table_entry *) 5749c20c4267SAnil Ravindranath &pinstance->cfg_table->entries_ext[i]; 575089a36810SAnil Ravindranath 5751c20c4267SAnil Ravindranath if (!pmcraid_expose_resource(fw_version, cfgte)) 575289a36810SAnil Ravindranath continue; 575389a36810SAnil Ravindranath 575489a36810SAnil Ravindranath found = 0; 575589a36810SAnil Ravindranath 575689a36810SAnil Ravindranath /* If this entry was already detected and initialized */ 575789a36810SAnil Ravindranath list_for_each_entry_safe(res, temp, &old_res, queue) { 575889a36810SAnil Ravindranath 575989a36810SAnil Ravindranath rc = memcmp(&res->cfg_entry.resource_address, 576089a36810SAnil Ravindranath &cfgte->resource_address, 576189a36810SAnil Ravindranath sizeof(cfgte->resource_address)); 576289a36810SAnil Ravindranath if (!rc) { 576389a36810SAnil Ravindranath list_move_tail(&res->queue, 576489a36810SAnil Ravindranath &pinstance->used_res_q); 576589a36810SAnil Ravindranath found = 1; 576689a36810SAnil Ravindranath break; 576789a36810SAnil Ravindranath } 576889a36810SAnil Ravindranath } 576989a36810SAnil Ravindranath 577089a36810SAnil Ravindranath /* If this is new entry, initialize it and add it the queue */ 577189a36810SAnil Ravindranath if (!found) { 577289a36810SAnil Ravindranath 577389a36810SAnil Ravindranath if (list_empty(&pinstance->free_res_q)) { 577434876402SAnil Ravindranath pmcraid_err("Too many devices attached\n"); 577589a36810SAnil Ravindranath break; 577689a36810SAnil Ravindranath } 577789a36810SAnil Ravindranath 577889a36810SAnil Ravindranath found = 1; 577989a36810SAnil Ravindranath res = list_entry(pinstance->free_res_q.next, 578089a36810SAnil Ravindranath struct pmcraid_resource_entry, queue); 578189a36810SAnil Ravindranath 578289a36810SAnil Ravindranath res->scsi_dev = NULL; 578389a36810SAnil Ravindranath res->change_detected = RES_CHANGE_ADD; 578489a36810SAnil Ravindranath res->reset_progress = 0; 578589a36810SAnil Ravindranath list_move_tail(&res->queue, &pinstance->used_res_q); 578689a36810SAnil Ravindranath } 578789a36810SAnil Ravindranath 578889a36810SAnil Ravindranath /* copy new configuration table entry details into driver 578989a36810SAnil Ravindranath * maintained resource entry 579089a36810SAnil Ravindranath */ 579189a36810SAnil Ravindranath if (found) { 579289a36810SAnil Ravindranath memcpy(&res->cfg_entry, cfgte, 5793c20c4267SAnil Ravindranath pinstance->config_table_entry_size); 579489a36810SAnil Ravindranath pmcraid_info("New res type:%x, vset:%x, addr:%x:\n", 579589a36810SAnil Ravindranath res->cfg_entry.resource_type, 5796c20c4267SAnil Ravindranath (fw_version <= PMCRAID_FW_VERSION_1 ? 5797c20c4267SAnil Ravindranath res->cfg_entry.unique_flags1 : 5798c20c4267SAnil Ravindranath res->cfg_entry.array_id & 0xFF), 579989a36810SAnil Ravindranath le32_to_cpu(res->cfg_entry.resource_address)); 580089a36810SAnil Ravindranath } 580189a36810SAnil Ravindranath } 580289a36810SAnil Ravindranath 580389a36810SAnil Ravindranath /* Detect any deleted entries, mark them for deletion from mid-layer */ 580489a36810SAnil Ravindranath list_for_each_entry_safe(res, temp, &old_res, queue) { 580589a36810SAnil Ravindranath 580689a36810SAnil Ravindranath if (res->scsi_dev) { 580789a36810SAnil Ravindranath res->change_detected = RES_CHANGE_DEL; 580889a36810SAnil Ravindranath res->cfg_entry.resource_handle = 580989a36810SAnil Ravindranath PMCRAID_INVALID_RES_HANDLE; 581089a36810SAnil Ravindranath list_move_tail(&res->queue, &pinstance->used_res_q); 581189a36810SAnil Ravindranath } else { 581289a36810SAnil Ravindranath list_move_tail(&res->queue, &pinstance->free_res_q); 581389a36810SAnil Ravindranath } 581489a36810SAnil Ravindranath } 581589a36810SAnil Ravindranath 581689a36810SAnil Ravindranath /* release the resource list lock */ 581789a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); 5818592488a3SAnil Ravindranath pmcraid_set_timestamp(cmd); 581989a36810SAnil Ravindranath } 582089a36810SAnil Ravindranath 582189a36810SAnil Ravindranath /** 582289a36810SAnil Ravindranath * pmcraid_querycfg - Send a Query IOA Config to the adapter. 582389a36810SAnil Ravindranath * @cmd: pointer pmcraid_cmd struct 582489a36810SAnil Ravindranath * 582589a36810SAnil Ravindranath * This function sends a Query IOA Configuration command to the adapter to 582689a36810SAnil Ravindranath * retrieve the IOA configuration table. 582789a36810SAnil Ravindranath * 582889a36810SAnil Ravindranath * Return value: 582989a36810SAnil Ravindranath * none 583089a36810SAnil Ravindranath */ 583189a36810SAnil Ravindranath static void pmcraid_querycfg(struct pmcraid_cmd *cmd) 583289a36810SAnil Ravindranath { 583389a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 583489a36810SAnil Ravindranath struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; 583589a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 583689a36810SAnil Ravindranath int cfg_table_size = cpu_to_be32(sizeof(struct pmcraid_config_table)); 583789a36810SAnil Ravindranath 5838c20c4267SAnil Ravindranath if (be16_to_cpu(pinstance->inq_data->fw_version) <= 5839c20c4267SAnil Ravindranath PMCRAID_FW_VERSION_1) 5840c20c4267SAnil Ravindranath pinstance->config_table_entry_size = 5841c20c4267SAnil Ravindranath sizeof(struct pmcraid_config_table_entry); 5842c20c4267SAnil Ravindranath else 5843c20c4267SAnil Ravindranath pinstance->config_table_entry_size = 5844c20c4267SAnil Ravindranath sizeof(struct pmcraid_config_table_entry_ext); 5845c20c4267SAnil Ravindranath 584689a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_IOACMD; 584789a36810SAnil Ravindranath ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); 584889a36810SAnil Ravindranath 584989a36810SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_QUERY_IOA_CONFIG; 585089a36810SAnil Ravindranath 585189a36810SAnil Ravindranath /* firmware requires 4-byte length field, specified in B.E format */ 585289a36810SAnil Ravindranath memcpy(&(ioarcb->cdb[10]), &cfg_table_size, sizeof(cfg_table_size)); 585389a36810SAnil Ravindranath 585489a36810SAnil Ravindranath /* Since entire config table can be described by single IOADL, it can 585589a36810SAnil Ravindranath * be part of IOARCB itself 585689a36810SAnil Ravindranath */ 585789a36810SAnil Ravindranath ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + 585889a36810SAnil Ravindranath offsetof(struct pmcraid_ioarcb, 585989a36810SAnil Ravindranath add_data.u.ioadl[0])); 586089a36810SAnil Ravindranath ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); 586189a36810SAnil Ravindranath ioarcb->ioarcb_bus_addr &= ~(0x1FULL); 586289a36810SAnil Ravindranath 586389a36810SAnil Ravindranath ioarcb->request_flags0 |= NO_LINK_DESCS; 586489a36810SAnil Ravindranath ioarcb->data_transfer_length = 586589a36810SAnil Ravindranath cpu_to_le32(sizeof(struct pmcraid_config_table)); 586689a36810SAnil Ravindranath 586789a36810SAnil Ravindranath ioadl = &(ioarcb->add_data.u.ioadl[0]); 586888197966SAnil Ravindranath ioadl->flags = IOADL_FLAGS_LAST_DESC; 586989a36810SAnil Ravindranath ioadl->address = cpu_to_le64(pinstance->cfg_table_bus_addr); 587089a36810SAnil Ravindranath ioadl->data_len = cpu_to_le32(sizeof(struct pmcraid_config_table)); 587189a36810SAnil Ravindranath 587289a36810SAnil Ravindranath pmcraid_send_cmd(cmd, pmcraid_init_res_table, 587389a36810SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler); 587489a36810SAnil Ravindranath } 587589a36810SAnil Ravindranath 587689a36810SAnil Ravindranath 587789a36810SAnil Ravindranath /** 5878c20c4267SAnil Ravindranath * pmcraid_probe - PCI probe entry pointer for PMC MaxRAID controller driver 587989a36810SAnil Ravindranath * @pdev: pointer to pci device structure 588089a36810SAnil Ravindranath * @dev_id: pointer to device ids structure 588189a36810SAnil Ravindranath * 588289a36810SAnil Ravindranath * Return Value 588389a36810SAnil Ravindranath * returns 0 if the device is claimed and successfully configured. 588489a36810SAnil Ravindranath * returns non-zero error code in case of any failure 588589a36810SAnil Ravindranath */ 588689a36810SAnil Ravindranath static int __devinit pmcraid_probe( 588789a36810SAnil Ravindranath struct pci_dev *pdev, 588889a36810SAnil Ravindranath const struct pci_device_id *dev_id 588989a36810SAnil Ravindranath ) 589089a36810SAnil Ravindranath { 589189a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 589289a36810SAnil Ravindranath struct Scsi_Host *host; 589389a36810SAnil Ravindranath void __iomem *mapped_pci_addr; 589489a36810SAnil Ravindranath int rc = PCIBIOS_SUCCESSFUL; 589589a36810SAnil Ravindranath 589689a36810SAnil Ravindranath if (atomic_read(&pmcraid_adapter_count) >= PMCRAID_MAX_ADAPTERS) { 589789a36810SAnil Ravindranath pmcraid_err 589889a36810SAnil Ravindranath ("maximum number(%d) of supported adapters reached\n", 589989a36810SAnil Ravindranath atomic_read(&pmcraid_adapter_count)); 590089a36810SAnil Ravindranath return -ENOMEM; 590189a36810SAnil Ravindranath } 590289a36810SAnil Ravindranath 590389a36810SAnil Ravindranath atomic_inc(&pmcraid_adapter_count); 590489a36810SAnil Ravindranath rc = pci_enable_device(pdev); 590589a36810SAnil Ravindranath 590689a36810SAnil Ravindranath if (rc) { 590789a36810SAnil Ravindranath dev_err(&pdev->dev, "Cannot enable adapter\n"); 590889a36810SAnil Ravindranath atomic_dec(&pmcraid_adapter_count); 590989a36810SAnil Ravindranath return rc; 591089a36810SAnil Ravindranath } 591189a36810SAnil Ravindranath 591289a36810SAnil Ravindranath dev_info(&pdev->dev, 591389a36810SAnil Ravindranath "Found new IOA(%x:%x), Total IOA count: %d\n", 591489a36810SAnil Ravindranath pdev->vendor, pdev->device, 591589a36810SAnil Ravindranath atomic_read(&pmcraid_adapter_count)); 591689a36810SAnil Ravindranath 591789a36810SAnil Ravindranath rc = pci_request_regions(pdev, PMCRAID_DRIVER_NAME); 591889a36810SAnil Ravindranath 591989a36810SAnil Ravindranath if (rc < 0) { 592089a36810SAnil Ravindranath dev_err(&pdev->dev, 592189a36810SAnil Ravindranath "Couldn't register memory range of registers\n"); 592289a36810SAnil Ravindranath goto out_disable_device; 592389a36810SAnil Ravindranath } 592489a36810SAnil Ravindranath 592589a36810SAnil Ravindranath mapped_pci_addr = pci_iomap(pdev, 0, 0); 592689a36810SAnil Ravindranath 592789a36810SAnil Ravindranath if (!mapped_pci_addr) { 592889a36810SAnil Ravindranath dev_err(&pdev->dev, "Couldn't map PCI registers memory\n"); 592989a36810SAnil Ravindranath rc = -ENOMEM; 593089a36810SAnil Ravindranath goto out_release_regions; 593189a36810SAnil Ravindranath } 593289a36810SAnil Ravindranath 593389a36810SAnil Ravindranath pci_set_master(pdev); 593489a36810SAnil Ravindranath 593589a36810SAnil Ravindranath /* Firmware requires the system bus address of IOARCB to be within 593689a36810SAnil Ravindranath * 32-bit addressable range though it has 64-bit IOARRIN register. 593789a36810SAnil Ravindranath * However, firmware supports 64-bit streaming DMA buffers, whereas 593889a36810SAnil Ravindranath * coherent buffers are to be 32-bit. Since pci_alloc_consistent always 593989a36810SAnil Ravindranath * returns memory within 4GB (if not, change this logic), coherent 594025985edcSLucas De Marchi * buffers are within firmware acceptable address ranges. 594189a36810SAnil Ravindranath */ 594289a36810SAnil Ravindranath if ((sizeof(dma_addr_t) == 4) || 594389a36810SAnil Ravindranath pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) 594489a36810SAnil Ravindranath rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 594589a36810SAnil Ravindranath 594689a36810SAnil Ravindranath /* firmware expects 32-bit DMA addresses for IOARRIN register; set 32 594789a36810SAnil Ravindranath * bit mask for pci_alloc_consistent to return addresses within 4GB 594889a36810SAnil Ravindranath */ 594989a36810SAnil Ravindranath if (rc == 0) 595089a36810SAnil Ravindranath rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); 595189a36810SAnil Ravindranath 595289a36810SAnil Ravindranath if (rc != 0) { 595389a36810SAnil Ravindranath dev_err(&pdev->dev, "Failed to set PCI DMA mask\n"); 595489a36810SAnil Ravindranath goto cleanup_nomem; 595589a36810SAnil Ravindranath } 595689a36810SAnil Ravindranath 595789a36810SAnil Ravindranath host = scsi_host_alloc(&pmcraid_host_template, 595889a36810SAnil Ravindranath sizeof(struct pmcraid_instance)); 595989a36810SAnil Ravindranath 596089a36810SAnil Ravindranath if (!host) { 596189a36810SAnil Ravindranath dev_err(&pdev->dev, "scsi_host_alloc failed!\n"); 596289a36810SAnil Ravindranath rc = -ENOMEM; 596389a36810SAnil Ravindranath goto cleanup_nomem; 596489a36810SAnil Ravindranath } 596589a36810SAnil Ravindranath 596689a36810SAnil Ravindranath host->max_id = PMCRAID_MAX_NUM_TARGETS_PER_BUS; 596789a36810SAnil Ravindranath host->max_lun = PMCRAID_MAX_NUM_LUNS_PER_TARGET; 596889a36810SAnil Ravindranath host->unique_id = host->host_no; 596989a36810SAnil Ravindranath host->max_channel = PMCRAID_MAX_BUS_TO_SCAN; 597089a36810SAnil Ravindranath host->max_cmd_len = PMCRAID_MAX_CDB_LEN; 597189a36810SAnil Ravindranath 597289a36810SAnil Ravindranath /* zero out entire instance structure */ 597389a36810SAnil Ravindranath pinstance = (struct pmcraid_instance *)host->hostdata; 597489a36810SAnil Ravindranath memset(pinstance, 0, sizeof(*pinstance)); 597589a36810SAnil Ravindranath 597689a36810SAnil Ravindranath pinstance->chip_cfg = 597789a36810SAnil Ravindranath (struct pmcraid_chip_details *)(dev_id->driver_data); 597889a36810SAnil Ravindranath 597989a36810SAnil Ravindranath rc = pmcraid_init_instance(pdev, host, mapped_pci_addr); 598089a36810SAnil Ravindranath 598189a36810SAnil Ravindranath if (rc < 0) { 598289a36810SAnil Ravindranath dev_err(&pdev->dev, "failed to initialize adapter instance\n"); 598389a36810SAnil Ravindranath goto out_scsi_host_put; 598489a36810SAnil Ravindranath } 598589a36810SAnil Ravindranath 598689a36810SAnil Ravindranath pci_set_drvdata(pdev, pinstance); 598789a36810SAnil Ravindranath 598889a36810SAnil Ravindranath /* Save PCI config-space for use following the reset */ 598989a36810SAnil Ravindranath rc = pci_save_state(pinstance->pdev); 599089a36810SAnil Ravindranath 599189a36810SAnil Ravindranath if (rc != 0) { 599289a36810SAnil Ravindranath dev_err(&pdev->dev, "Failed to save PCI config space\n"); 599389a36810SAnil Ravindranath goto out_scsi_host_put; 599489a36810SAnil Ravindranath } 599589a36810SAnil Ravindranath 599689a36810SAnil Ravindranath pmcraid_disable_interrupts(pinstance, ~0); 599789a36810SAnil Ravindranath 599889a36810SAnil Ravindranath rc = pmcraid_register_interrupt_handler(pinstance); 599989a36810SAnil Ravindranath 600089a36810SAnil Ravindranath if (rc) { 600134876402SAnil Ravindranath dev_err(&pdev->dev, "couldn't register interrupt handler\n"); 600289a36810SAnil Ravindranath goto out_scsi_host_put; 600389a36810SAnil Ravindranath } 600489a36810SAnil Ravindranath 600589a36810SAnil Ravindranath pmcraid_init_tasklets(pinstance); 600689a36810SAnil Ravindranath 600789a36810SAnil Ravindranath /* allocate verious buffers used by LLD.*/ 600889a36810SAnil Ravindranath rc = pmcraid_init_buffers(pinstance); 600989a36810SAnil Ravindranath 601089a36810SAnil Ravindranath if (rc) { 601189a36810SAnil Ravindranath pmcraid_err("couldn't allocate memory blocks\n"); 601289a36810SAnil Ravindranath goto out_unregister_isr; 601389a36810SAnil Ravindranath } 601489a36810SAnil Ravindranath 601589a36810SAnil Ravindranath /* check the reset type required */ 601689a36810SAnil Ravindranath pmcraid_reset_type(pinstance); 601789a36810SAnil Ravindranath 601889a36810SAnil Ravindranath pmcraid_enable_interrupts(pinstance, PMCRAID_PCI_INTERRUPTS); 601989a36810SAnil Ravindranath 602089a36810SAnil Ravindranath /* Start IOA firmware initialization and bring card to Operational 602189a36810SAnil Ravindranath * state. 602289a36810SAnil Ravindranath */ 602389a36810SAnil Ravindranath pmcraid_info("starting IOA initialization sequence\n"); 602489a36810SAnil Ravindranath if (pmcraid_reset_bringup(pinstance)) { 602534876402SAnil Ravindranath dev_err(&pdev->dev, "couldn't initialize IOA\n"); 602689a36810SAnil Ravindranath rc = 1; 602789a36810SAnil Ravindranath goto out_release_bufs; 602889a36810SAnil Ravindranath } 602989a36810SAnil Ravindranath 603089a36810SAnil Ravindranath /* Add adapter instance into mid-layer list */ 603189a36810SAnil Ravindranath rc = scsi_add_host(pinstance->host, &pdev->dev); 603289a36810SAnil Ravindranath if (rc != 0) { 603389a36810SAnil Ravindranath pmcraid_err("couldn't add host into mid-layer: %d\n", rc); 603489a36810SAnil Ravindranath goto out_release_bufs; 603589a36810SAnil Ravindranath } 603689a36810SAnil Ravindranath 603789a36810SAnil Ravindranath scsi_scan_host(pinstance->host); 603889a36810SAnil Ravindranath 603989a36810SAnil Ravindranath rc = pmcraid_setup_chrdev(pinstance); 604089a36810SAnil Ravindranath 604189a36810SAnil Ravindranath if (rc != 0) { 604289a36810SAnil Ravindranath pmcraid_err("couldn't create mgmt interface, error: %x\n", 604389a36810SAnil Ravindranath rc); 604489a36810SAnil Ravindranath goto out_remove_host; 604589a36810SAnil Ravindranath } 604689a36810SAnil Ravindranath 604789a36810SAnil Ravindranath /* Schedule worker thread to handle CCN and take care of adding and 604889a36810SAnil Ravindranath * removing devices to OS 604989a36810SAnil Ravindranath */ 605089a36810SAnil Ravindranath atomic_set(&pinstance->expose_resources, 1); 605189a36810SAnil Ravindranath schedule_work(&pinstance->worker_q); 605289a36810SAnil Ravindranath return rc; 605389a36810SAnil Ravindranath 605489a36810SAnil Ravindranath out_remove_host: 605589a36810SAnil Ravindranath scsi_remove_host(host); 605689a36810SAnil Ravindranath 605789a36810SAnil Ravindranath out_release_bufs: 605889a36810SAnil Ravindranath pmcraid_release_buffers(pinstance); 605989a36810SAnil Ravindranath 606089a36810SAnil Ravindranath out_unregister_isr: 606189a36810SAnil Ravindranath pmcraid_kill_tasklets(pinstance); 606289a36810SAnil Ravindranath pmcraid_unregister_interrupt_handler(pinstance); 606389a36810SAnil Ravindranath 606489a36810SAnil Ravindranath out_scsi_host_put: 606589a36810SAnil Ravindranath scsi_host_put(host); 606689a36810SAnil Ravindranath 606789a36810SAnil Ravindranath cleanup_nomem: 606889a36810SAnil Ravindranath iounmap(mapped_pci_addr); 606989a36810SAnil Ravindranath 607089a36810SAnil Ravindranath out_release_regions: 607189a36810SAnil Ravindranath pci_release_regions(pdev); 607289a36810SAnil Ravindranath 607389a36810SAnil Ravindranath out_disable_device: 607489a36810SAnil Ravindranath atomic_dec(&pmcraid_adapter_count); 607589a36810SAnil Ravindranath pci_set_drvdata(pdev, NULL); 607689a36810SAnil Ravindranath pci_disable_device(pdev); 607789a36810SAnil Ravindranath return -ENODEV; 607889a36810SAnil Ravindranath } 607989a36810SAnil Ravindranath 608089a36810SAnil Ravindranath /* 608189a36810SAnil Ravindranath * PCI driver structure of pcmraid driver 608289a36810SAnil Ravindranath */ 608389a36810SAnil Ravindranath static struct pci_driver pmcraid_driver = { 608489a36810SAnil Ravindranath .name = PMCRAID_DRIVER_NAME, 608589a36810SAnil Ravindranath .id_table = pmcraid_pci_table, 608689a36810SAnil Ravindranath .probe = pmcraid_probe, 608789a36810SAnil Ravindranath .remove = pmcraid_remove, 608889a36810SAnil Ravindranath .suspend = pmcraid_suspend, 608989a36810SAnil Ravindranath .resume = pmcraid_resume, 609089a36810SAnil Ravindranath .shutdown = pmcraid_shutdown 609189a36810SAnil Ravindranath }; 609289a36810SAnil Ravindranath 609389a36810SAnil Ravindranath /** 609489a36810SAnil Ravindranath * pmcraid_init - module load entry point 609589a36810SAnil Ravindranath */ 609689a36810SAnil Ravindranath static int __init pmcraid_init(void) 609789a36810SAnil Ravindranath { 609889a36810SAnil Ravindranath dev_t dev; 609989a36810SAnil Ravindranath int error; 610089a36810SAnil Ravindranath 6101a1b66665SMichal Marek pmcraid_info("%s Device Driver version: %s\n", 6102a1b66665SMichal Marek PMCRAID_DRIVER_NAME, PMCRAID_DRIVER_VERSION); 610389a36810SAnil Ravindranath 610489a36810SAnil Ravindranath error = alloc_chrdev_region(&dev, 0, 610589a36810SAnil Ravindranath PMCRAID_MAX_ADAPTERS, 610689a36810SAnil Ravindranath PMCRAID_DEVFILE); 610789a36810SAnil Ravindranath 610889a36810SAnil Ravindranath if (error) { 610989a36810SAnil Ravindranath pmcraid_err("failed to get a major number for adapters\n"); 611089a36810SAnil Ravindranath goto out_init; 611189a36810SAnil Ravindranath } 611289a36810SAnil Ravindranath 611389a36810SAnil Ravindranath pmcraid_major = MAJOR(dev); 611489a36810SAnil Ravindranath pmcraid_class = class_create(THIS_MODULE, PMCRAID_DEVFILE); 611589a36810SAnil Ravindranath 611689a36810SAnil Ravindranath if (IS_ERR(pmcraid_class)) { 611789a36810SAnil Ravindranath error = PTR_ERR(pmcraid_class); 611889a36810SAnil Ravindranath pmcraid_err("failed to register with with sysfs, error = %x\n", 611989a36810SAnil Ravindranath error); 612089a36810SAnil Ravindranath goto out_unreg_chrdev; 612189a36810SAnil Ravindranath } 612289a36810SAnil Ravindranath 612389a36810SAnil Ravindranath error = pmcraid_netlink_init(); 612489a36810SAnil Ravindranath 612589a36810SAnil Ravindranath if (error) 612689a36810SAnil Ravindranath goto out_unreg_chrdev; 612789a36810SAnil Ravindranath 612889a36810SAnil Ravindranath error = pci_register_driver(&pmcraid_driver); 612989a36810SAnil Ravindranath 613089a36810SAnil Ravindranath if (error == 0) 613189a36810SAnil Ravindranath goto out_init; 613289a36810SAnil Ravindranath 613389a36810SAnil Ravindranath pmcraid_err("failed to register pmcraid driver, error = %x\n", 613489a36810SAnil Ravindranath error); 613589a36810SAnil Ravindranath class_destroy(pmcraid_class); 613689a36810SAnil Ravindranath pmcraid_netlink_release(); 613789a36810SAnil Ravindranath 613889a36810SAnil Ravindranath out_unreg_chrdev: 613989a36810SAnil Ravindranath unregister_chrdev_region(MKDEV(pmcraid_major, 0), PMCRAID_MAX_ADAPTERS); 614034876402SAnil Ravindranath 614189a36810SAnil Ravindranath out_init: 614289a36810SAnil Ravindranath return error; 614389a36810SAnil Ravindranath } 614489a36810SAnil Ravindranath 614589a36810SAnil Ravindranath /** 614689a36810SAnil Ravindranath * pmcraid_exit - module unload entry point 614789a36810SAnil Ravindranath */ 614889a36810SAnil Ravindranath static void __exit pmcraid_exit(void) 614989a36810SAnil Ravindranath { 615089a36810SAnil Ravindranath pmcraid_netlink_release(); 615189a36810SAnil Ravindranath unregister_chrdev_region(MKDEV(pmcraid_major, 0), 615289a36810SAnil Ravindranath PMCRAID_MAX_ADAPTERS); 615389a36810SAnil Ravindranath pci_unregister_driver(&pmcraid_driver); 6154592488a3SAnil Ravindranath class_destroy(pmcraid_class); 615589a36810SAnil Ravindranath } 615689a36810SAnil Ravindranath 615789a36810SAnil Ravindranath module_init(pmcraid_init); 615889a36810SAnil Ravindranath module_exit(pmcraid_exit); 6159