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> 489c9bd593SAlison Schofield #include <linux/ktime.h> 4989a36810SAnil Ravindranath #include <scsi/scsi.h> 5089a36810SAnil Ravindranath #include <scsi/scsi_host.h> 5134876402SAnil Ravindranath #include <scsi/scsi_device.h> 5289a36810SAnil Ravindranath #include <scsi/scsi_tcq.h> 5389a36810SAnil Ravindranath #include <scsi/scsi_eh.h> 5489a36810SAnil Ravindranath #include <scsi/scsi_cmnd.h> 5589a36810SAnil Ravindranath #include <scsi/scsicam.h> 5689a36810SAnil Ravindranath 5789a36810SAnil Ravindranath #include "pmcraid.h" 5889a36810SAnil Ravindranath 5989a36810SAnil Ravindranath /* 6089a36810SAnil Ravindranath * Module configuration parameters 6189a36810SAnil Ravindranath */ 6289a36810SAnil Ravindranath static unsigned int pmcraid_debug_log; 6389a36810SAnil Ravindranath static unsigned int pmcraid_disable_aen; 6489a36810SAnil Ravindranath static unsigned int pmcraid_log_level = IOASC_LOG_LEVEL_MUST; 655da61410SAnil Ravindranath static unsigned int pmcraid_enable_msix; 6689a36810SAnil Ravindranath 6789a36810SAnil Ravindranath /* 6889a36810SAnil Ravindranath * Data structures to support multiple adapters by the LLD. 6989a36810SAnil Ravindranath * pmcraid_adapter_count - count of configured adapters 7089a36810SAnil Ravindranath */ 7189a36810SAnil Ravindranath static atomic_t pmcraid_adapter_count = ATOMIC_INIT(0); 7289a36810SAnil Ravindranath 7389a36810SAnil Ravindranath /* 7489a36810SAnil Ravindranath * Supporting user-level control interface through IOCTL commands. 7589a36810SAnil Ravindranath * pmcraid_major - major number to use 7689a36810SAnil Ravindranath * pmcraid_minor - minor number(s) to use 7789a36810SAnil Ravindranath */ 7889a36810SAnil Ravindranath static unsigned int pmcraid_major; 7989a36810SAnil Ravindranath static struct class *pmcraid_class; 8089a36810SAnil Ravindranath DECLARE_BITMAP(pmcraid_minor, PMCRAID_MAX_ADAPTERS); 8189a36810SAnil Ravindranath 8289a36810SAnil Ravindranath /* 8389a36810SAnil Ravindranath * Module parameters 8489a36810SAnil Ravindranath */ 85729c8456SAnil Ravindranath MODULE_AUTHOR("Anil Ravindranath<anil_ravindranath@pmc-sierra.com>"); 8689a36810SAnil Ravindranath MODULE_DESCRIPTION("PMC Sierra MaxRAID Controller Driver"); 8789a36810SAnil Ravindranath MODULE_LICENSE("GPL"); 8889a36810SAnil Ravindranath MODULE_VERSION(PMCRAID_DRIVER_VERSION); 8989a36810SAnil Ravindranath 9089a36810SAnil Ravindranath module_param_named(log_level, pmcraid_log_level, uint, (S_IRUGO | S_IWUSR)); 9189a36810SAnil Ravindranath MODULE_PARM_DESC(log_level, 9289a36810SAnil Ravindranath "Enables firmware error code logging, default :1 high-severity" 9389a36810SAnil Ravindranath " errors, 2: all errors including high-severity errors," 9489a36810SAnil Ravindranath " 0: disables logging"); 9589a36810SAnil Ravindranath 9689a36810SAnil Ravindranath module_param_named(debug, pmcraid_debug_log, uint, (S_IRUGO | S_IWUSR)); 9789a36810SAnil Ravindranath MODULE_PARM_DESC(debug, 9889a36810SAnil Ravindranath "Enable driver verbose message logging. Set 1 to enable." 9989a36810SAnil Ravindranath "(default: 0)"); 10089a36810SAnil Ravindranath 10189a36810SAnil Ravindranath module_param_named(disable_aen, pmcraid_disable_aen, uint, (S_IRUGO | S_IWUSR)); 10289a36810SAnil Ravindranath MODULE_PARM_DESC(disable_aen, 10389a36810SAnil Ravindranath "Disable driver aen notifications to apps. Set 1 to disable." 10489a36810SAnil Ravindranath "(default: 0)"); 10589a36810SAnil Ravindranath 10689a36810SAnil Ravindranath /* chip specific constants for PMC MaxRAID controllers (same for 10789a36810SAnil Ravindranath * 0x5220 and 0x8010 10889a36810SAnil Ravindranath */ 10989a36810SAnil Ravindranath static struct pmcraid_chip_details pmcraid_chip_cfg[] = { 11089a36810SAnil Ravindranath { 11189a36810SAnil Ravindranath .ioastatus = 0x0, 11289a36810SAnil Ravindranath .ioarrin = 0x00040, 11389a36810SAnil Ravindranath .mailbox = 0x7FC30, 11489a36810SAnil Ravindranath .global_intr_mask = 0x00034, 11589a36810SAnil Ravindranath .ioa_host_intr = 0x0009C, 11689a36810SAnil Ravindranath .ioa_host_intr_clr = 0x000A0, 117c20c4267SAnil Ravindranath .ioa_host_msix_intr = 0x7FC40, 11889a36810SAnil Ravindranath .ioa_host_mask = 0x7FC28, 11989a36810SAnil Ravindranath .ioa_host_mask_clr = 0x7FC28, 12089a36810SAnil Ravindranath .host_ioa_intr = 0x00020, 12189a36810SAnil Ravindranath .host_ioa_intr_clr = 0x00020, 12289a36810SAnil Ravindranath .transop_timeout = 300 12389a36810SAnil Ravindranath } 12489a36810SAnil Ravindranath }; 12589a36810SAnil Ravindranath 12689a36810SAnil Ravindranath /* 12789a36810SAnil Ravindranath * PCI device ids supported by pmcraid driver 12889a36810SAnil Ravindranath */ 1296f039790SGreg Kroah-Hartman static struct pci_device_id pmcraid_pci_table[] = { 13089a36810SAnil Ravindranath { PCI_DEVICE(PCI_VENDOR_ID_PMC, PCI_DEVICE_ID_PMC_MAXRAID), 13189a36810SAnil Ravindranath 0, 0, (kernel_ulong_t)&pmcraid_chip_cfg[0] 13289a36810SAnil Ravindranath }, 13389a36810SAnil Ravindranath {} 13489a36810SAnil Ravindranath }; 13589a36810SAnil Ravindranath 13689a36810SAnil Ravindranath MODULE_DEVICE_TABLE(pci, pmcraid_pci_table); 13789a36810SAnil Ravindranath 13889a36810SAnil Ravindranath 13989a36810SAnil Ravindranath 14089a36810SAnil Ravindranath /** 14189a36810SAnil Ravindranath * pmcraid_slave_alloc - Prepare for commands to a device 14289a36810SAnil Ravindranath * @scsi_dev: scsi device struct 14389a36810SAnil Ravindranath * 14489a36810SAnil Ravindranath * This function is called by mid-layer prior to sending any command to the new 14589a36810SAnil Ravindranath * device. Stores resource entry details of the device in scsi_device struct. 14689a36810SAnil Ravindranath * Queuecommand uses the resource handle and other details to fill up IOARCB 14789a36810SAnil Ravindranath * while sending commands to the device. 14889a36810SAnil Ravindranath * 14989a36810SAnil Ravindranath * Return value: 15089a36810SAnil Ravindranath * 0 on success / -ENXIO if device does not exist 15189a36810SAnil Ravindranath */ 15289a36810SAnil Ravindranath static int pmcraid_slave_alloc(struct scsi_device *scsi_dev) 15389a36810SAnil Ravindranath { 15489a36810SAnil Ravindranath struct pmcraid_resource_entry *temp, *res = NULL; 15589a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 15689a36810SAnil Ravindranath u8 target, bus, lun; 15789a36810SAnil Ravindranath unsigned long lock_flags; 15889a36810SAnil Ravindranath int rc = -ENXIO; 159c20c4267SAnil Ravindranath u16 fw_version; 160c20c4267SAnil Ravindranath 16189a36810SAnil Ravindranath pinstance = shost_priv(scsi_dev->host); 16289a36810SAnil Ravindranath 163c20c4267SAnil Ravindranath fw_version = be16_to_cpu(pinstance->inq_data->fw_version); 164c20c4267SAnil Ravindranath 16589a36810SAnil Ravindranath /* Driver exposes VSET and GSCSI resources only; all other device types 16689a36810SAnil Ravindranath * are not exposed. Resource list is synchronized using resource lock 16789a36810SAnil Ravindranath * so any traversal or modifications to the list should be done inside 16889a36810SAnil Ravindranath * this lock 16989a36810SAnil Ravindranath */ 17089a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->resource_lock, lock_flags); 17189a36810SAnil Ravindranath list_for_each_entry(temp, &pinstance->used_res_q, queue) { 17289a36810SAnil Ravindranath 173729c8456SAnil Ravindranath /* do not expose VSETs with order-ids > MAX_VSET_TARGETS */ 17489a36810SAnil Ravindranath if (RES_IS_VSET(temp->cfg_entry)) { 175c20c4267SAnil Ravindranath if (fw_version <= PMCRAID_FW_VERSION_1) 17689a36810SAnil Ravindranath target = temp->cfg_entry.unique_flags1; 177c20c4267SAnil Ravindranath else 17845c80be6SArnd Bergmann target = le16_to_cpu(temp->cfg_entry.array_id) & 0xFF; 179c20c4267SAnil Ravindranath 180729c8456SAnil Ravindranath if (target > PMCRAID_MAX_VSET_TARGETS) 18189a36810SAnil Ravindranath continue; 18289a36810SAnil Ravindranath bus = PMCRAID_VSET_BUS_ID; 18389a36810SAnil Ravindranath lun = 0; 18489a36810SAnil Ravindranath } else if (RES_IS_GSCSI(temp->cfg_entry)) { 18589a36810SAnil Ravindranath target = RES_TARGET(temp->cfg_entry.resource_address); 18689a36810SAnil Ravindranath bus = PMCRAID_PHYS_BUS_ID; 18789a36810SAnil Ravindranath lun = RES_LUN(temp->cfg_entry.resource_address); 18889a36810SAnil Ravindranath } else { 18989a36810SAnil Ravindranath continue; 19089a36810SAnil Ravindranath } 19189a36810SAnil Ravindranath 19289a36810SAnil Ravindranath if (bus == scsi_dev->channel && 19389a36810SAnil Ravindranath target == scsi_dev->id && 19489a36810SAnil Ravindranath lun == scsi_dev->lun) { 19589a36810SAnil Ravindranath res = temp; 19689a36810SAnil Ravindranath break; 19789a36810SAnil Ravindranath } 19889a36810SAnil Ravindranath } 19989a36810SAnil Ravindranath 20089a36810SAnil Ravindranath if (res) { 20189a36810SAnil Ravindranath res->scsi_dev = scsi_dev; 20289a36810SAnil Ravindranath scsi_dev->hostdata = res; 20389a36810SAnil Ravindranath res->change_detected = 0; 20489a36810SAnil Ravindranath atomic_set(&res->read_failures, 0); 20589a36810SAnil Ravindranath atomic_set(&res->write_failures, 0); 20689a36810SAnil Ravindranath rc = 0; 20789a36810SAnil Ravindranath } 20889a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); 20989a36810SAnil Ravindranath return rc; 21089a36810SAnil Ravindranath } 21189a36810SAnil Ravindranath 21289a36810SAnil Ravindranath /** 21389a36810SAnil Ravindranath * pmcraid_slave_configure - Configures a SCSI device 21489a36810SAnil Ravindranath * @scsi_dev: scsi device struct 21589a36810SAnil Ravindranath * 21625985edcSLucas De Marchi * This function is executed by SCSI mid layer just after a device is first 21789a36810SAnil Ravindranath * scanned (i.e. it has responded to an INQUIRY). For VSET resources, the 21889a36810SAnil Ravindranath * timeout value (default 30s) will be over-written to a higher value (60s) 21989a36810SAnil Ravindranath * and max_sectors value will be over-written to 512. It also sets queue depth 22089a36810SAnil Ravindranath * to host->cmd_per_lun value 22189a36810SAnil Ravindranath * 22289a36810SAnil Ravindranath * Return value: 22389a36810SAnil Ravindranath * 0 on success 22489a36810SAnil Ravindranath */ 22589a36810SAnil Ravindranath static int pmcraid_slave_configure(struct scsi_device *scsi_dev) 22689a36810SAnil Ravindranath { 22789a36810SAnil Ravindranath struct pmcraid_resource_entry *res = scsi_dev->hostdata; 22889a36810SAnil Ravindranath 22989a36810SAnil Ravindranath if (!res) 23089a36810SAnil Ravindranath return 0; 23189a36810SAnil Ravindranath 23289a36810SAnil Ravindranath /* LLD exposes VSETs and Enclosure devices only */ 23389a36810SAnil Ravindranath if (RES_IS_GSCSI(res->cfg_entry) && 23489a36810SAnil Ravindranath scsi_dev->type != TYPE_ENCLOSURE) 23589a36810SAnil Ravindranath return -ENXIO; 23689a36810SAnil Ravindranath 23789a36810SAnil Ravindranath pmcraid_info("configuring %x:%x:%x:%x\n", 23889a36810SAnil Ravindranath scsi_dev->host->unique_id, 23989a36810SAnil Ravindranath scsi_dev->channel, 24089a36810SAnil Ravindranath scsi_dev->id, 2419cb78c16SHannes Reinecke (u8)scsi_dev->lun); 24289a36810SAnil Ravindranath 24389a36810SAnil Ravindranath if (RES_IS_GSCSI(res->cfg_entry)) { 24489a36810SAnil Ravindranath scsi_dev->allow_restart = 1; 24589a36810SAnil Ravindranath } else if (RES_IS_VSET(res->cfg_entry)) { 24689a36810SAnil Ravindranath scsi_dev->allow_restart = 1; 24789a36810SAnil Ravindranath blk_queue_rq_timeout(scsi_dev->request_queue, 24889a36810SAnil Ravindranath PMCRAID_VSET_IO_TIMEOUT); 249086fa5ffSMartin K. Petersen blk_queue_max_hw_sectors(scsi_dev->request_queue, 25089a36810SAnil Ravindranath PMCRAID_VSET_MAX_SECTORS); 25189a36810SAnil Ravindranath } 25289a36810SAnil Ravindranath 253c8b09f6fSChristoph Hellwig /* 254c8b09f6fSChristoph Hellwig * We never want to report TCQ support for these types of devices. 255c8b09f6fSChristoph Hellwig */ 256c8b09f6fSChristoph Hellwig if (!RES_IS_GSCSI(res->cfg_entry) && !RES_IS_VSET(res->cfg_entry)) 257c8b09f6fSChristoph Hellwig scsi_dev->tagged_supported = 0; 25889a36810SAnil Ravindranath 25989a36810SAnil Ravindranath return 0; 26089a36810SAnil Ravindranath } 26189a36810SAnil Ravindranath 26289a36810SAnil Ravindranath /** 26389a36810SAnil Ravindranath * pmcraid_slave_destroy - Unconfigure a SCSI device before removing it 26489a36810SAnil Ravindranath * 26589a36810SAnil Ravindranath * @scsi_dev: scsi device struct 26689a36810SAnil Ravindranath * 26789a36810SAnil Ravindranath * This is called by mid-layer before removing a device. Pointer assignments 26889a36810SAnil Ravindranath * done in pmcraid_slave_alloc will be reset to NULL here. 26989a36810SAnil Ravindranath * 27089a36810SAnil Ravindranath * Return value 27189a36810SAnil Ravindranath * none 27289a36810SAnil Ravindranath */ 27389a36810SAnil Ravindranath static void pmcraid_slave_destroy(struct scsi_device *scsi_dev) 27489a36810SAnil Ravindranath { 27589a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 27689a36810SAnil Ravindranath 27789a36810SAnil Ravindranath res = (struct pmcraid_resource_entry *)scsi_dev->hostdata; 27889a36810SAnil Ravindranath 27989a36810SAnil Ravindranath if (res) 28089a36810SAnil Ravindranath res->scsi_dev = NULL; 28189a36810SAnil Ravindranath 28289a36810SAnil Ravindranath scsi_dev->hostdata = NULL; 28389a36810SAnil Ravindranath } 28489a36810SAnil Ravindranath 28589a36810SAnil Ravindranath /** 28689a36810SAnil Ravindranath * pmcraid_change_queue_depth - Change the device's queue depth 28789a36810SAnil Ravindranath * @scsi_dev: scsi device struct 28889a36810SAnil Ravindranath * @depth: depth to set 28989a36810SAnil Ravindranath * 29089a36810SAnil Ravindranath * Return value 29189a36810SAnil Ravindranath * actual depth set 29289a36810SAnil Ravindranath */ 293db5ed4dfSChristoph Hellwig static int pmcraid_change_queue_depth(struct scsi_device *scsi_dev, int depth) 29489a36810SAnil Ravindranath { 29589a36810SAnil Ravindranath if (depth > PMCRAID_MAX_CMD_PER_LUN) 29689a36810SAnil Ravindranath depth = PMCRAID_MAX_CMD_PER_LUN; 297db5ed4dfSChristoph Hellwig return scsi_change_queue_depth(scsi_dev, depth); 29889a36810SAnil Ravindranath } 29989a36810SAnil Ravindranath 30089a36810SAnil Ravindranath /** 30189a36810SAnil Ravindranath * pmcraid_init_cmdblk - initializes a command block 30289a36810SAnil Ravindranath * 30389a36810SAnil Ravindranath * @cmd: pointer to struct pmcraid_cmd to be initialized 30489a36810SAnil Ravindranath * @index: if >=0 first time initialization; otherwise reinitialization 30589a36810SAnil Ravindranath * 30689a36810SAnil Ravindranath * Return Value 30789a36810SAnil Ravindranath * None 30889a36810SAnil Ravindranath */ 30961b96d5bSBaoyou Xie static void pmcraid_init_cmdblk(struct pmcraid_cmd *cmd, int index) 31089a36810SAnil Ravindranath { 31189a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &(cmd->ioa_cb->ioarcb); 31289a36810SAnil Ravindranath dma_addr_t dma_addr = cmd->ioa_cb_bus_addr; 31389a36810SAnil Ravindranath 31489a36810SAnil Ravindranath if (index >= 0) { 31589a36810SAnil Ravindranath /* first time initialization (called from probe) */ 31689a36810SAnil Ravindranath u32 ioasa_offset = 31789a36810SAnil Ravindranath offsetof(struct pmcraid_control_block, ioasa); 31889a36810SAnil Ravindranath 31989a36810SAnil Ravindranath cmd->index = index; 32089a36810SAnil Ravindranath ioarcb->response_handle = cpu_to_le32(index << 2); 32189a36810SAnil Ravindranath ioarcb->ioarcb_bus_addr = cpu_to_le64(dma_addr); 32289a36810SAnil Ravindranath ioarcb->ioasa_bus_addr = cpu_to_le64(dma_addr + ioasa_offset); 32389a36810SAnil Ravindranath ioarcb->ioasa_len = cpu_to_le16(sizeof(struct pmcraid_ioasa)); 32489a36810SAnil Ravindranath } else { 32589a36810SAnil Ravindranath /* re-initialization of various lengths, called once command is 32689a36810SAnil Ravindranath * processed by IOA 32789a36810SAnil Ravindranath */ 32889a36810SAnil Ravindranath memset(&cmd->ioa_cb->ioarcb.cdb, 0, PMCRAID_MAX_CDB_LEN); 329c20c4267SAnil Ravindranath ioarcb->hrrq_id = 0; 33089a36810SAnil Ravindranath ioarcb->request_flags0 = 0; 33189a36810SAnil Ravindranath ioarcb->request_flags1 = 0; 33289a36810SAnil Ravindranath ioarcb->cmd_timeout = 0; 33345c80be6SArnd Bergmann ioarcb->ioarcb_bus_addr &= cpu_to_le64(~0x1FULL); 33489a36810SAnil Ravindranath ioarcb->ioadl_bus_addr = 0; 33589a36810SAnil Ravindranath ioarcb->ioadl_length = 0; 33689a36810SAnil Ravindranath ioarcb->data_transfer_length = 0; 33789a36810SAnil Ravindranath ioarcb->add_cmd_param_length = 0; 33889a36810SAnil Ravindranath ioarcb->add_cmd_param_offset = 0; 33989a36810SAnil Ravindranath cmd->ioa_cb->ioasa.ioasc = 0; 34089a36810SAnil Ravindranath cmd->ioa_cb->ioasa.residual_data_length = 0; 341c20c4267SAnil Ravindranath cmd->time_left = 0; 34289a36810SAnil Ravindranath } 34389a36810SAnil Ravindranath 34489a36810SAnil Ravindranath cmd->cmd_done = NULL; 34589a36810SAnil Ravindranath cmd->scsi_cmd = NULL; 34689a36810SAnil Ravindranath cmd->release = 0; 34789a36810SAnil Ravindranath cmd->completion_req = 0; 348c20c4267SAnil Ravindranath cmd->sense_buffer = 0; 349c20c4267SAnil Ravindranath cmd->sense_buffer_dma = 0; 35089a36810SAnil Ravindranath cmd->dma_handle = 0; 35189a36810SAnil Ravindranath init_timer(&cmd->timer); 35289a36810SAnil Ravindranath } 35389a36810SAnil Ravindranath 35489a36810SAnil Ravindranath /** 35589a36810SAnil Ravindranath * pmcraid_reinit_cmdblk - reinitialize a command block 35689a36810SAnil Ravindranath * 35789a36810SAnil Ravindranath * @cmd: pointer to struct pmcraid_cmd to be reinitialized 35889a36810SAnil Ravindranath * 35989a36810SAnil Ravindranath * Return Value 36089a36810SAnil Ravindranath * None 36189a36810SAnil Ravindranath */ 36289a36810SAnil Ravindranath static void pmcraid_reinit_cmdblk(struct pmcraid_cmd *cmd) 36389a36810SAnil Ravindranath { 36489a36810SAnil Ravindranath pmcraid_init_cmdblk(cmd, -1); 36589a36810SAnil Ravindranath } 36689a36810SAnil Ravindranath 36789a36810SAnil Ravindranath /** 36889a36810SAnil Ravindranath * pmcraid_get_free_cmd - get a free cmd block from command block pool 36989a36810SAnil Ravindranath * @pinstance: adapter instance structure 37089a36810SAnil Ravindranath * 37189a36810SAnil Ravindranath * Return Value: 37289a36810SAnil Ravindranath * returns pointer to cmd block or NULL if no blocks are available 37389a36810SAnil Ravindranath */ 37489a36810SAnil Ravindranath static struct pmcraid_cmd *pmcraid_get_free_cmd( 37589a36810SAnil Ravindranath struct pmcraid_instance *pinstance 37689a36810SAnil Ravindranath ) 37789a36810SAnil Ravindranath { 37889a36810SAnil Ravindranath struct pmcraid_cmd *cmd = NULL; 37989a36810SAnil Ravindranath unsigned long lock_flags; 38089a36810SAnil Ravindranath 38189a36810SAnil Ravindranath /* free cmd block list is protected by free_pool_lock */ 38289a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->free_pool_lock, lock_flags); 38389a36810SAnil Ravindranath 38489a36810SAnil Ravindranath if (!list_empty(&pinstance->free_cmd_pool)) { 38589a36810SAnil Ravindranath cmd = list_entry(pinstance->free_cmd_pool.next, 38689a36810SAnil Ravindranath struct pmcraid_cmd, free_list); 38789a36810SAnil Ravindranath list_del(&cmd->free_list); 38889a36810SAnil Ravindranath } 38989a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->free_pool_lock, lock_flags); 39089a36810SAnil Ravindranath 39189a36810SAnil Ravindranath /* Initialize the command block before giving it the caller */ 39289a36810SAnil Ravindranath if (cmd != NULL) 39389a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 39489a36810SAnil Ravindranath return cmd; 39589a36810SAnil Ravindranath } 39689a36810SAnil Ravindranath 39789a36810SAnil Ravindranath /** 39889a36810SAnil Ravindranath * pmcraid_return_cmd - return a completed command block back into free pool 39989a36810SAnil Ravindranath * @cmd: pointer to the command block 40089a36810SAnil Ravindranath * 40189a36810SAnil Ravindranath * Return Value: 40289a36810SAnil Ravindranath * nothing 40389a36810SAnil Ravindranath */ 40461b96d5bSBaoyou Xie static void pmcraid_return_cmd(struct pmcraid_cmd *cmd) 40589a36810SAnil Ravindranath { 40689a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 40789a36810SAnil Ravindranath unsigned long lock_flags; 40889a36810SAnil Ravindranath 40989a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->free_pool_lock, lock_flags); 41089a36810SAnil Ravindranath list_add_tail(&cmd->free_list, &pinstance->free_cmd_pool); 41189a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->free_pool_lock, lock_flags); 41289a36810SAnil Ravindranath } 41389a36810SAnil Ravindranath 41489a36810SAnil Ravindranath /** 41589a36810SAnil Ravindranath * pmcraid_read_interrupts - reads IOA interrupts 41689a36810SAnil Ravindranath * 41789a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 41889a36810SAnil Ravindranath * 41989a36810SAnil Ravindranath * Return value 42089a36810SAnil Ravindranath * interrupts read from IOA 42189a36810SAnil Ravindranath */ 42289a36810SAnil Ravindranath static u32 pmcraid_read_interrupts(struct pmcraid_instance *pinstance) 42389a36810SAnil Ravindranath { 424c20c4267SAnil Ravindranath return (pinstance->interrupt_mode) ? 425c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.ioa_host_msix_interrupt_reg) : 426c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.ioa_host_interrupt_reg); 42789a36810SAnil Ravindranath } 42889a36810SAnil Ravindranath 42989a36810SAnil Ravindranath /** 43089a36810SAnil Ravindranath * pmcraid_disable_interrupts - Masks and clears all specified interrupts 43189a36810SAnil Ravindranath * 43289a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 43389a36810SAnil Ravindranath * @intrs: interrupts to disable 43489a36810SAnil Ravindranath * 43589a36810SAnil Ravindranath * Return Value 43689a36810SAnil Ravindranath * None 43789a36810SAnil Ravindranath */ 43889a36810SAnil Ravindranath static void pmcraid_disable_interrupts( 43989a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 44089a36810SAnil Ravindranath u32 intrs 44189a36810SAnil Ravindranath ) 44289a36810SAnil Ravindranath { 44389a36810SAnil Ravindranath u32 gmask = ioread32(pinstance->int_regs.global_interrupt_mask_reg); 44489a36810SAnil Ravindranath u32 nmask = gmask | GLOBAL_INTERRUPT_MASK; 44589a36810SAnil Ravindranath 44689a36810SAnil Ravindranath iowrite32(intrs, pinstance->int_regs.ioa_host_interrupt_clr_reg); 447c20c4267SAnil Ravindranath iowrite32(nmask, pinstance->int_regs.global_interrupt_mask_reg); 448c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.global_interrupt_mask_reg); 449c20c4267SAnil Ravindranath 450c20c4267SAnil Ravindranath if (!pinstance->interrupt_mode) { 451c20c4267SAnil Ravindranath iowrite32(intrs, 452c20c4267SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_mask_reg); 45389a36810SAnil Ravindranath ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg); 45489a36810SAnil Ravindranath } 455c20c4267SAnil Ravindranath } 45689a36810SAnil Ravindranath 45789a36810SAnil Ravindranath /** 45889a36810SAnil Ravindranath * pmcraid_enable_interrupts - Enables specified interrupts 45989a36810SAnil Ravindranath * 46089a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 46189a36810SAnil Ravindranath * @intr: interrupts to enable 46289a36810SAnil Ravindranath * 46389a36810SAnil Ravindranath * Return Value 46489a36810SAnil Ravindranath * None 46589a36810SAnil Ravindranath */ 46689a36810SAnil Ravindranath static void pmcraid_enable_interrupts( 46789a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 46889a36810SAnil Ravindranath u32 intrs 46989a36810SAnil Ravindranath ) 47089a36810SAnil Ravindranath { 47189a36810SAnil Ravindranath u32 gmask = ioread32(pinstance->int_regs.global_interrupt_mask_reg); 47289a36810SAnil Ravindranath u32 nmask = gmask & (~GLOBAL_INTERRUPT_MASK); 47389a36810SAnil Ravindranath 47489a36810SAnil Ravindranath iowrite32(nmask, pinstance->int_regs.global_interrupt_mask_reg); 475c20c4267SAnil Ravindranath 476c20c4267SAnil Ravindranath if (!pinstance->interrupt_mode) { 477c20c4267SAnil Ravindranath iowrite32(~intrs, 478c20c4267SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_mask_reg); 47989a36810SAnil Ravindranath ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg); 480c20c4267SAnil Ravindranath } 48189a36810SAnil Ravindranath 48289a36810SAnil Ravindranath pmcraid_info("enabled interrupts global mask = %x intr_mask = %x\n", 48389a36810SAnil Ravindranath ioread32(pinstance->int_regs.global_interrupt_mask_reg), 48489a36810SAnil Ravindranath ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg)); 48589a36810SAnil Ravindranath } 48689a36810SAnil Ravindranath 48789a36810SAnil Ravindranath /** 488c20c4267SAnil Ravindranath * pmcraid_clr_trans_op - clear trans to op interrupt 489c20c4267SAnil Ravindranath * 490c20c4267SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 491c20c4267SAnil Ravindranath * 492c20c4267SAnil Ravindranath * Return Value 493c20c4267SAnil Ravindranath * None 494c20c4267SAnil Ravindranath */ 495c20c4267SAnil Ravindranath static void pmcraid_clr_trans_op( 496c20c4267SAnil Ravindranath struct pmcraid_instance *pinstance 497c20c4267SAnil Ravindranath ) 498c20c4267SAnil Ravindranath { 499c20c4267SAnil Ravindranath unsigned long lock_flags; 500c20c4267SAnil Ravindranath 501c20c4267SAnil Ravindranath if (!pinstance->interrupt_mode) { 502c20c4267SAnil Ravindranath iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, 503c20c4267SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_mask_reg); 504c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg); 505c20c4267SAnil Ravindranath iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, 506c20c4267SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_clr_reg); 507c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.ioa_host_interrupt_clr_reg); 508c20c4267SAnil Ravindranath } 509c20c4267SAnil Ravindranath 510c20c4267SAnil Ravindranath if (pinstance->reset_cmd != NULL) { 511c20c4267SAnil Ravindranath del_timer(&pinstance->reset_cmd->timer); 512c20c4267SAnil Ravindranath spin_lock_irqsave( 513c20c4267SAnil Ravindranath pinstance->host->host_lock, lock_flags); 514c20c4267SAnil Ravindranath pinstance->reset_cmd->cmd_done(pinstance->reset_cmd); 515c20c4267SAnil Ravindranath spin_unlock_irqrestore( 516c20c4267SAnil Ravindranath pinstance->host->host_lock, lock_flags); 517c20c4267SAnil Ravindranath } 518c20c4267SAnil Ravindranath } 519c20c4267SAnil Ravindranath 520c20c4267SAnil Ravindranath /** 52189a36810SAnil Ravindranath * pmcraid_reset_type - Determine the required reset type 52289a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 52389a36810SAnil Ravindranath * 52489a36810SAnil Ravindranath * IOA requires hard reset if any of the following conditions is true. 52589a36810SAnil Ravindranath * 1. If HRRQ valid interrupt is not masked 52689a36810SAnil Ravindranath * 2. IOA reset alert doorbell is set 52789a36810SAnil Ravindranath * 3. If there are any error interrupts 52889a36810SAnil Ravindranath */ 52989a36810SAnil Ravindranath static void pmcraid_reset_type(struct pmcraid_instance *pinstance) 53089a36810SAnil Ravindranath { 53189a36810SAnil Ravindranath u32 mask; 53289a36810SAnil Ravindranath u32 intrs; 53389a36810SAnil Ravindranath u32 alerts; 53489a36810SAnil Ravindranath 53589a36810SAnil Ravindranath mask = ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg); 53689a36810SAnil Ravindranath intrs = ioread32(pinstance->int_regs.ioa_host_interrupt_reg); 53789a36810SAnil Ravindranath alerts = ioread32(pinstance->int_regs.host_ioa_interrupt_reg); 53889a36810SAnil Ravindranath 53989a36810SAnil Ravindranath if ((mask & INTRS_HRRQ_VALID) == 0 || 54089a36810SAnil Ravindranath (alerts & DOORBELL_IOA_RESET_ALERT) || 54189a36810SAnil Ravindranath (intrs & PMCRAID_ERROR_INTERRUPTS)) { 54289a36810SAnil Ravindranath pmcraid_info("IOA requires hard reset\n"); 54389a36810SAnil Ravindranath pinstance->ioa_hard_reset = 1; 54489a36810SAnil Ravindranath } 54589a36810SAnil Ravindranath 54689a36810SAnil Ravindranath /* If unit check is active, trigger the dump */ 54789a36810SAnil Ravindranath if (intrs & INTRS_IOA_UNIT_CHECK) 54889a36810SAnil Ravindranath pinstance->ioa_unit_check = 1; 54989a36810SAnil Ravindranath } 55089a36810SAnil Ravindranath 55189a36810SAnil Ravindranath /** 55289a36810SAnil Ravindranath * pmcraid_bist_done - completion function for PCI BIST 55389a36810SAnil Ravindranath * @cmd: pointer to reset command 55489a36810SAnil Ravindranath * Return Value 55589a36810SAnil Ravindranath * none 55689a36810SAnil Ravindranath */ 55789a36810SAnil Ravindranath 55889a36810SAnil Ravindranath static void pmcraid_ioa_reset(struct pmcraid_cmd *); 55989a36810SAnil Ravindranath 56089a36810SAnil Ravindranath static void pmcraid_bist_done(struct pmcraid_cmd *cmd) 56189a36810SAnil Ravindranath { 56289a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 56389a36810SAnil Ravindranath unsigned long lock_flags; 56489a36810SAnil Ravindranath int rc; 56589a36810SAnil Ravindranath u16 pci_reg; 56689a36810SAnil Ravindranath 56789a36810SAnil Ravindranath rc = pci_read_config_word(pinstance->pdev, PCI_COMMAND, &pci_reg); 56889a36810SAnil Ravindranath 56989a36810SAnil Ravindranath /* If PCI config space can't be accessed wait for another two secs */ 57089a36810SAnil Ravindranath if ((rc != PCIBIOS_SUCCESSFUL || (!(pci_reg & PCI_COMMAND_MEMORY))) && 571c20c4267SAnil Ravindranath cmd->time_left > 0) { 57289a36810SAnil Ravindranath pmcraid_info("BIST not complete, waiting another 2 secs\n"); 573c20c4267SAnil Ravindranath cmd->timer.expires = jiffies + cmd->time_left; 574c20c4267SAnil Ravindranath cmd->time_left = 0; 57589a36810SAnil Ravindranath cmd->timer.data = (unsigned long)cmd; 57689a36810SAnil Ravindranath cmd->timer.function = 57789a36810SAnil Ravindranath (void (*)(unsigned long))pmcraid_bist_done; 57889a36810SAnil Ravindranath add_timer(&cmd->timer); 57989a36810SAnil Ravindranath } else { 580c20c4267SAnil Ravindranath cmd->time_left = 0; 58189a36810SAnil Ravindranath pmcraid_info("BIST is complete, proceeding with reset\n"); 58289a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 58389a36810SAnil Ravindranath pmcraid_ioa_reset(cmd); 58489a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 58589a36810SAnil Ravindranath } 58689a36810SAnil Ravindranath } 58789a36810SAnil Ravindranath 58889a36810SAnil Ravindranath /** 58989a36810SAnil Ravindranath * pmcraid_start_bist - starts BIST 59089a36810SAnil Ravindranath * @cmd: pointer to reset cmd 59189a36810SAnil Ravindranath * Return Value 59289a36810SAnil Ravindranath * none 59389a36810SAnil Ravindranath */ 59489a36810SAnil Ravindranath static void pmcraid_start_bist(struct pmcraid_cmd *cmd) 59589a36810SAnil Ravindranath { 59689a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 59789a36810SAnil Ravindranath u32 doorbells, intrs; 59889a36810SAnil Ravindranath 59989a36810SAnil Ravindranath /* proceed with bist and wait for 2 seconds */ 60089a36810SAnil Ravindranath iowrite32(DOORBELL_IOA_START_BIST, 60189a36810SAnil Ravindranath pinstance->int_regs.host_ioa_interrupt_reg); 60289a36810SAnil Ravindranath doorbells = ioread32(pinstance->int_regs.host_ioa_interrupt_reg); 60389a36810SAnil Ravindranath intrs = ioread32(pinstance->int_regs.ioa_host_interrupt_reg); 60489a36810SAnil Ravindranath pmcraid_info("doorbells after start bist: %x intrs: %x\n", 60589a36810SAnil Ravindranath doorbells, intrs); 60689a36810SAnil Ravindranath 607c20c4267SAnil Ravindranath cmd->time_left = msecs_to_jiffies(PMCRAID_BIST_TIMEOUT); 60889a36810SAnil Ravindranath cmd->timer.data = (unsigned long)cmd; 60989a36810SAnil Ravindranath cmd->timer.expires = jiffies + msecs_to_jiffies(PMCRAID_BIST_TIMEOUT); 61089a36810SAnil Ravindranath cmd->timer.function = (void (*)(unsigned long))pmcraid_bist_done; 61189a36810SAnil Ravindranath add_timer(&cmd->timer); 61289a36810SAnil Ravindranath } 61389a36810SAnil Ravindranath 61489a36810SAnil Ravindranath /** 61589a36810SAnil Ravindranath * pmcraid_reset_alert_done - completion routine for reset_alert 61689a36810SAnil Ravindranath * @cmd: pointer to command block used in reset sequence 61789a36810SAnil Ravindranath * Return value 61889a36810SAnil Ravindranath * None 61989a36810SAnil Ravindranath */ 62089a36810SAnil Ravindranath static void pmcraid_reset_alert_done(struct pmcraid_cmd *cmd) 62189a36810SAnil Ravindranath { 62289a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 62389a36810SAnil Ravindranath u32 status = ioread32(pinstance->ioa_status); 62489a36810SAnil Ravindranath unsigned long lock_flags; 62589a36810SAnil Ravindranath 62689a36810SAnil Ravindranath /* if the critical operation in progress bit is set or the wait times 62789a36810SAnil Ravindranath * out, invoke reset engine to proceed with hard reset. If there is 62889a36810SAnil Ravindranath * some more time to wait, restart the timer 62989a36810SAnil Ravindranath */ 63089a36810SAnil Ravindranath if (((status & INTRS_CRITICAL_OP_IN_PROGRESS) == 0) || 631c20c4267SAnil Ravindranath cmd->time_left <= 0) { 63289a36810SAnil Ravindranath pmcraid_info("critical op is reset proceeding with reset\n"); 63389a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 63489a36810SAnil Ravindranath pmcraid_ioa_reset(cmd); 63589a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 63689a36810SAnil Ravindranath } else { 63789a36810SAnil Ravindranath pmcraid_info("critical op is not yet reset waiting again\n"); 63889a36810SAnil Ravindranath /* restart timer if some more time is available to wait */ 639c20c4267SAnil Ravindranath cmd->time_left -= PMCRAID_CHECK_FOR_RESET_TIMEOUT; 64089a36810SAnil Ravindranath cmd->timer.data = (unsigned long)cmd; 64189a36810SAnil Ravindranath cmd->timer.expires = jiffies + PMCRAID_CHECK_FOR_RESET_TIMEOUT; 64289a36810SAnil Ravindranath cmd->timer.function = 64389a36810SAnil Ravindranath (void (*)(unsigned long))pmcraid_reset_alert_done; 64489a36810SAnil Ravindranath add_timer(&cmd->timer); 64589a36810SAnil Ravindranath } 64689a36810SAnil Ravindranath } 64789a36810SAnil Ravindranath 64889a36810SAnil Ravindranath /** 64989a36810SAnil Ravindranath * pmcraid_reset_alert - alerts IOA for a possible reset 65089a36810SAnil Ravindranath * @cmd : command block to be used for reset sequence. 65189a36810SAnil Ravindranath * 65289a36810SAnil Ravindranath * Return Value 65389a36810SAnil Ravindranath * returns 0 if pci config-space is accessible and RESET_DOORBELL is 65489a36810SAnil Ravindranath * successfully written to IOA. Returns non-zero in case pci_config_space 65589a36810SAnil Ravindranath * is not accessible 65689a36810SAnil Ravindranath */ 657c20c4267SAnil Ravindranath static void pmcraid_notify_ioastate(struct pmcraid_instance *, u32); 65889a36810SAnil Ravindranath static void pmcraid_reset_alert(struct pmcraid_cmd *cmd) 65989a36810SAnil Ravindranath { 66089a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 66189a36810SAnil Ravindranath u32 doorbells; 66289a36810SAnil Ravindranath int rc; 66389a36810SAnil Ravindranath u16 pci_reg; 66489a36810SAnil Ravindranath 66589a36810SAnil Ravindranath /* If we are able to access IOA PCI config space, alert IOA that we are 66689a36810SAnil Ravindranath * going to reset it soon. This enables IOA to preserv persistent error 66789a36810SAnil Ravindranath * data if any. In case memory space is not accessible, proceed with 66889a36810SAnil Ravindranath * BIST or slot_reset 66989a36810SAnil Ravindranath */ 67089a36810SAnil Ravindranath rc = pci_read_config_word(pinstance->pdev, PCI_COMMAND, &pci_reg); 67189a36810SAnil Ravindranath if ((rc == PCIBIOS_SUCCESSFUL) && (pci_reg & PCI_COMMAND_MEMORY)) { 67289a36810SAnil Ravindranath 67389a36810SAnil Ravindranath /* wait for IOA permission i.e until CRITICAL_OPERATION bit is 67489a36810SAnil Ravindranath * reset IOA doesn't generate any interrupts when CRITICAL 67589a36810SAnil Ravindranath * OPERATION bit is reset. A timer is started to wait for this 67689a36810SAnil Ravindranath * bit to be reset. 67789a36810SAnil Ravindranath */ 678c20c4267SAnil Ravindranath cmd->time_left = PMCRAID_RESET_TIMEOUT; 67989a36810SAnil Ravindranath cmd->timer.data = (unsigned long)cmd; 68089a36810SAnil Ravindranath cmd->timer.expires = jiffies + PMCRAID_CHECK_FOR_RESET_TIMEOUT; 68189a36810SAnil Ravindranath cmd->timer.function = 68289a36810SAnil Ravindranath (void (*)(unsigned long))pmcraid_reset_alert_done; 68389a36810SAnil Ravindranath add_timer(&cmd->timer); 68489a36810SAnil Ravindranath 68589a36810SAnil Ravindranath iowrite32(DOORBELL_IOA_RESET_ALERT, 68689a36810SAnil Ravindranath pinstance->int_regs.host_ioa_interrupt_reg); 68789a36810SAnil Ravindranath doorbells = 68889a36810SAnil Ravindranath ioread32(pinstance->int_regs.host_ioa_interrupt_reg); 68989a36810SAnil Ravindranath pmcraid_info("doorbells after reset alert: %x\n", doorbells); 69089a36810SAnil Ravindranath } else { 69189a36810SAnil Ravindranath pmcraid_info("PCI config is not accessible starting BIST\n"); 69289a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_HARD_RESET; 69389a36810SAnil Ravindranath pmcraid_start_bist(cmd); 69489a36810SAnil Ravindranath } 69589a36810SAnil Ravindranath } 69689a36810SAnil Ravindranath 69789a36810SAnil Ravindranath /** 69889a36810SAnil Ravindranath * pmcraid_timeout_handler - Timeout handler for internally generated ops 69989a36810SAnil Ravindranath * 70089a36810SAnil Ravindranath * @cmd : pointer to command structure, that got timedout 70189a36810SAnil Ravindranath * 70289a36810SAnil Ravindranath * This function blocks host requests and initiates an adapter reset. 70389a36810SAnil Ravindranath * 70489a36810SAnil Ravindranath * Return value: 70589a36810SAnil Ravindranath * None 70689a36810SAnil Ravindranath */ 70789a36810SAnil Ravindranath static void pmcraid_timeout_handler(struct pmcraid_cmd *cmd) 70889a36810SAnil Ravindranath { 70989a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 71089a36810SAnil Ravindranath unsigned long lock_flags; 71189a36810SAnil Ravindranath 71234876402SAnil Ravindranath dev_info(&pinstance->pdev->dev, 713c20c4267SAnil Ravindranath "Adapter being reset due to cmd(CDB[0] = %x) timeout\n", 714c20c4267SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0]); 71589a36810SAnil Ravindranath 71689a36810SAnil Ravindranath /* Command timeouts result in hard reset sequence. The command that got 71789a36810SAnil Ravindranath * timed out may be the one used as part of reset sequence. In this 71889a36810SAnil Ravindranath * case restart reset sequence using the same command block even if 71989a36810SAnil Ravindranath * reset is in progress. Otherwise fail this command and get a free 72089a36810SAnil Ravindranath * command block to restart the reset sequence. 72189a36810SAnil Ravindranath */ 72289a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 72389a36810SAnil Ravindranath if (!pinstance->ioa_reset_in_progress) { 72489a36810SAnil Ravindranath pinstance->ioa_reset_attempts = 0; 72589a36810SAnil Ravindranath cmd = pmcraid_get_free_cmd(pinstance); 72689a36810SAnil Ravindranath 72789a36810SAnil Ravindranath /* If we are out of command blocks, just return here itself. 72889a36810SAnil Ravindranath * Some other command's timeout handler can do the reset job 72989a36810SAnil Ravindranath */ 73089a36810SAnil Ravindranath if (cmd == NULL) { 73189a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 73289a36810SAnil Ravindranath lock_flags); 73389a36810SAnil Ravindranath pmcraid_err("no free cmnd block for timeout handler\n"); 73489a36810SAnil Ravindranath return; 73589a36810SAnil Ravindranath } 73689a36810SAnil Ravindranath 73789a36810SAnil Ravindranath pinstance->reset_cmd = cmd; 73889a36810SAnil Ravindranath pinstance->ioa_reset_in_progress = 1; 73989a36810SAnil Ravindranath } else { 74089a36810SAnil Ravindranath pmcraid_info("reset is already in progress\n"); 74189a36810SAnil Ravindranath 74289a36810SAnil Ravindranath if (pinstance->reset_cmd != cmd) { 74389a36810SAnil Ravindranath /* This command should have been given to IOA, this 74489a36810SAnil Ravindranath * command will be completed by fail_outstanding_cmds 74589a36810SAnil Ravindranath * anyway 74689a36810SAnil Ravindranath */ 74789a36810SAnil Ravindranath pmcraid_err("cmd is pending but reset in progress\n"); 74889a36810SAnil Ravindranath } 74989a36810SAnil Ravindranath 75089a36810SAnil Ravindranath /* If this command was being used as part of the reset 75189a36810SAnil Ravindranath * sequence, set cmd_done pointer to pmcraid_ioa_reset. This 75289a36810SAnil Ravindranath * causes fail_outstanding_commands not to return the command 75389a36810SAnil Ravindranath * block back to free pool 75489a36810SAnil Ravindranath */ 75589a36810SAnil Ravindranath if (cmd == pinstance->reset_cmd) 75689a36810SAnil Ravindranath cmd->cmd_done = pmcraid_ioa_reset; 75789a36810SAnil Ravindranath } 75889a36810SAnil Ravindranath 759c20c4267SAnil Ravindranath /* Notify apps of important IOA bringup/bringdown sequences */ 760c20c4267SAnil Ravindranath if (pinstance->scn.ioa_state != PMC_DEVICE_EVENT_RESET_START && 761c20c4267SAnil Ravindranath pinstance->scn.ioa_state != PMC_DEVICE_EVENT_SHUTDOWN_START) 762c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, 763c20c4267SAnil Ravindranath PMC_DEVICE_EVENT_RESET_START); 764c20c4267SAnil Ravindranath 76589a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; 76689a36810SAnil Ravindranath scsi_block_requests(pinstance->host); 76789a36810SAnil Ravindranath pmcraid_reset_alert(cmd); 76889a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 76989a36810SAnil Ravindranath } 77089a36810SAnil Ravindranath 77189a36810SAnil Ravindranath /** 77289a36810SAnil Ravindranath * pmcraid_internal_done - completion routine for internally generated cmds 77389a36810SAnil Ravindranath * 77489a36810SAnil Ravindranath * @cmd: command that got response from IOA 77589a36810SAnil Ravindranath * 77689a36810SAnil Ravindranath * Return Value: 77789a36810SAnil Ravindranath * none 77889a36810SAnil Ravindranath */ 77989a36810SAnil Ravindranath static void pmcraid_internal_done(struct pmcraid_cmd *cmd) 78089a36810SAnil Ravindranath { 78189a36810SAnil Ravindranath pmcraid_info("response internal cmd CDB[0] = %x ioasc = %x\n", 78289a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 78389a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)); 78489a36810SAnil Ravindranath 78589a36810SAnil Ravindranath /* Some of the internal commands are sent with callers blocking for the 78689a36810SAnil Ravindranath * response. Same will be indicated as part of cmd->completion_req 78789a36810SAnil Ravindranath * field. Response path needs to wake up any waiters waiting for cmd 78889a36810SAnil Ravindranath * completion if this flag is set. 78989a36810SAnil Ravindranath */ 79089a36810SAnil Ravindranath if (cmd->completion_req) { 79189a36810SAnil Ravindranath cmd->completion_req = 0; 79289a36810SAnil Ravindranath complete(&cmd->wait_for_completion); 79389a36810SAnil Ravindranath } 79489a36810SAnil Ravindranath 79589a36810SAnil Ravindranath /* most of the internal commands are completed by caller itself, so 79689a36810SAnil Ravindranath * no need to return the command block back to free pool until we are 79789a36810SAnil Ravindranath * required to do so (e.g once done with initialization). 79889a36810SAnil Ravindranath */ 79989a36810SAnil Ravindranath if (cmd->release) { 80089a36810SAnil Ravindranath cmd->release = 0; 80189a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 80289a36810SAnil Ravindranath } 80389a36810SAnil Ravindranath } 80489a36810SAnil Ravindranath 80589a36810SAnil Ravindranath /** 80689a36810SAnil Ravindranath * pmcraid_reinit_cfgtable_done - done function for cfg table reinitialization 80789a36810SAnil Ravindranath * 80889a36810SAnil Ravindranath * @cmd: command that got response from IOA 80989a36810SAnil Ravindranath * 81089a36810SAnil Ravindranath * This routine is called after driver re-reads configuration table due to a 81189a36810SAnil Ravindranath * lost CCN. It returns the command block back to free pool and schedules 81289a36810SAnil Ravindranath * worker thread to add/delete devices into the system. 81389a36810SAnil Ravindranath * 81489a36810SAnil Ravindranath * Return Value: 81589a36810SAnil Ravindranath * none 81689a36810SAnil Ravindranath */ 81789a36810SAnil Ravindranath static void pmcraid_reinit_cfgtable_done(struct pmcraid_cmd *cmd) 81889a36810SAnil Ravindranath { 81989a36810SAnil Ravindranath pmcraid_info("response internal cmd CDB[0] = %x ioasc = %x\n", 82089a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 82189a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)); 82289a36810SAnil Ravindranath 82389a36810SAnil Ravindranath if (cmd->release) { 82489a36810SAnil Ravindranath cmd->release = 0; 82589a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 82689a36810SAnil Ravindranath } 82789a36810SAnil Ravindranath pmcraid_info("scheduling worker for config table reinitialization\n"); 82889a36810SAnil Ravindranath schedule_work(&cmd->drv_inst->worker_q); 82989a36810SAnil Ravindranath } 83089a36810SAnil Ravindranath 83189a36810SAnil Ravindranath /** 83289a36810SAnil Ravindranath * pmcraid_erp_done - Process completion of SCSI error response from device 83389a36810SAnil Ravindranath * @cmd: pmcraid_command 83489a36810SAnil Ravindranath * 83589a36810SAnil Ravindranath * This function copies the sense buffer into the scsi_cmd struct and completes 83689a36810SAnil Ravindranath * scsi_cmd by calling scsi_done function. 83789a36810SAnil Ravindranath * 83889a36810SAnil Ravindranath * Return value: 83989a36810SAnil Ravindranath * none 84089a36810SAnil Ravindranath */ 84189a36810SAnil Ravindranath static void pmcraid_erp_done(struct pmcraid_cmd *cmd) 84289a36810SAnil Ravindranath { 84389a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; 84489a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 84589a36810SAnil Ravindranath u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); 84689a36810SAnil Ravindranath 84789a36810SAnil Ravindranath if (PMCRAID_IOASC_SENSE_KEY(ioasc) > 0) { 84889a36810SAnil Ravindranath scsi_cmd->result |= (DID_ERROR << 16); 84934876402SAnil Ravindranath scmd_printk(KERN_INFO, scsi_cmd, 85034876402SAnil Ravindranath "command CDB[0] = %x failed with IOASC: 0x%08X\n", 85189a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], ioasc); 85289a36810SAnil Ravindranath } 85389a36810SAnil Ravindranath 85489a36810SAnil Ravindranath /* if we had allocated sense buffers for request sense, copy the sense 85589a36810SAnil Ravindranath * release the buffers 85689a36810SAnil Ravindranath */ 85789a36810SAnil Ravindranath if (cmd->sense_buffer != NULL) { 85889a36810SAnil Ravindranath memcpy(scsi_cmd->sense_buffer, 85989a36810SAnil Ravindranath cmd->sense_buffer, 86089a36810SAnil Ravindranath SCSI_SENSE_BUFFERSIZE); 86189a36810SAnil Ravindranath pci_free_consistent(pinstance->pdev, 86289a36810SAnil Ravindranath SCSI_SENSE_BUFFERSIZE, 86389a36810SAnil Ravindranath cmd->sense_buffer, cmd->sense_buffer_dma); 86489a36810SAnil Ravindranath cmd->sense_buffer = NULL; 86589a36810SAnil Ravindranath cmd->sense_buffer_dma = 0; 86689a36810SAnil Ravindranath } 86789a36810SAnil Ravindranath 86889a36810SAnil Ravindranath scsi_dma_unmap(scsi_cmd); 86989a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 87089a36810SAnil Ravindranath scsi_cmd->scsi_done(scsi_cmd); 87189a36810SAnil Ravindranath } 87289a36810SAnil Ravindranath 87389a36810SAnil Ravindranath /** 87489a36810SAnil Ravindranath * pmcraid_fire_command - sends an IOA command to adapter 87589a36810SAnil Ravindranath * 87689a36810SAnil Ravindranath * This function adds the given block into pending command list 87789a36810SAnil Ravindranath * and returns without waiting 87889a36810SAnil Ravindranath * 87989a36810SAnil Ravindranath * @cmd : command to be sent to the device 88089a36810SAnil Ravindranath * 88189a36810SAnil Ravindranath * Return Value 88289a36810SAnil Ravindranath * None 88389a36810SAnil Ravindranath */ 88489a36810SAnil Ravindranath static void _pmcraid_fire_command(struct pmcraid_cmd *cmd) 88589a36810SAnil Ravindranath { 88689a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 88789a36810SAnil Ravindranath unsigned long lock_flags; 88889a36810SAnil Ravindranath 88989a36810SAnil Ravindranath /* Add this command block to pending cmd pool. We do this prior to 89089a36810SAnil Ravindranath * writting IOARCB to ioarrin because IOA might complete the command 89189a36810SAnil Ravindranath * by the time we are about to add it to the list. Response handler 892c20c4267SAnil Ravindranath * (isr/tasklet) looks for cmd block in the pending pending list. 89389a36810SAnil Ravindranath */ 89489a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->pending_pool_lock, lock_flags); 89589a36810SAnil Ravindranath list_add_tail(&cmd->free_list, &pinstance->pending_cmd_pool); 89689a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->pending_pool_lock, lock_flags); 89789a36810SAnil Ravindranath atomic_inc(&pinstance->outstanding_cmds); 89889a36810SAnil Ravindranath 89989a36810SAnil Ravindranath /* driver writes lower 32-bit value of IOARCB address only */ 90089a36810SAnil Ravindranath mb(); 90145c80be6SArnd Bergmann iowrite32(le64_to_cpu(cmd->ioa_cb->ioarcb.ioarcb_bus_addr), pinstance->ioarrin); 90289a36810SAnil Ravindranath } 90389a36810SAnil Ravindranath 90489a36810SAnil Ravindranath /** 90589a36810SAnil Ravindranath * pmcraid_send_cmd - fires a command to IOA 90689a36810SAnil Ravindranath * 90789a36810SAnil Ravindranath * This function also sets up timeout function, and command completion 90889a36810SAnil Ravindranath * function 90989a36810SAnil Ravindranath * 91089a36810SAnil Ravindranath * @cmd: pointer to the command block to be fired to IOA 91189a36810SAnil Ravindranath * @cmd_done: command completion function, called once IOA responds 91289a36810SAnil Ravindranath * @timeout: timeout to wait for this command completion 91389a36810SAnil Ravindranath * @timeout_func: timeout handler 91489a36810SAnil Ravindranath * 91589a36810SAnil Ravindranath * Return value 91689a36810SAnil Ravindranath * none 91789a36810SAnil Ravindranath */ 91889a36810SAnil Ravindranath static void pmcraid_send_cmd( 91989a36810SAnil Ravindranath struct pmcraid_cmd *cmd, 92089a36810SAnil Ravindranath void (*cmd_done) (struct pmcraid_cmd *), 92189a36810SAnil Ravindranath unsigned long timeout, 92289a36810SAnil Ravindranath void (*timeout_func) (struct pmcraid_cmd *) 92389a36810SAnil Ravindranath ) 92489a36810SAnil Ravindranath { 92589a36810SAnil Ravindranath /* initialize done function */ 92689a36810SAnil Ravindranath cmd->cmd_done = cmd_done; 92789a36810SAnil Ravindranath 92889a36810SAnil Ravindranath if (timeout_func) { 92989a36810SAnil Ravindranath /* setup timeout handler */ 93089a36810SAnil Ravindranath cmd->timer.data = (unsigned long)cmd; 93189a36810SAnil Ravindranath cmd->timer.expires = jiffies + timeout; 93289a36810SAnil Ravindranath cmd->timer.function = (void (*)(unsigned long))timeout_func; 93389a36810SAnil Ravindranath add_timer(&cmd->timer); 93489a36810SAnil Ravindranath } 93589a36810SAnil Ravindranath 93689a36810SAnil Ravindranath /* fire the command to IOA */ 93789a36810SAnil Ravindranath _pmcraid_fire_command(cmd); 93889a36810SAnil Ravindranath } 93989a36810SAnil Ravindranath 94089a36810SAnil Ravindranath /** 941c20c4267SAnil Ravindranath * pmcraid_ioa_shutdown_done - completion function for IOA shutdown command 942c20c4267SAnil Ravindranath * @cmd: pointer to the command block used for sending IOA shutdown command 943c20c4267SAnil Ravindranath * 944c20c4267SAnil Ravindranath * Return value 945c20c4267SAnil Ravindranath * None 946c20c4267SAnil Ravindranath */ 947c20c4267SAnil Ravindranath static void pmcraid_ioa_shutdown_done(struct pmcraid_cmd *cmd) 948c20c4267SAnil Ravindranath { 949c20c4267SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 950c20c4267SAnil Ravindranath unsigned long lock_flags; 951c20c4267SAnil Ravindranath 952c20c4267SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 953c20c4267SAnil Ravindranath pmcraid_ioa_reset(cmd); 954c20c4267SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 955c20c4267SAnil Ravindranath } 956c20c4267SAnil Ravindranath 957c20c4267SAnil Ravindranath /** 95889a36810SAnil Ravindranath * pmcraid_ioa_shutdown - sends SHUTDOWN command to ioa 95989a36810SAnil Ravindranath * 96089a36810SAnil Ravindranath * @cmd: pointer to the command block used as part of reset sequence 96189a36810SAnil Ravindranath * 96289a36810SAnil Ravindranath * Return Value 96389a36810SAnil Ravindranath * None 96489a36810SAnil Ravindranath */ 96589a36810SAnil Ravindranath static void pmcraid_ioa_shutdown(struct pmcraid_cmd *cmd) 96689a36810SAnil Ravindranath { 96789a36810SAnil Ravindranath pmcraid_info("response for Cancel CCN CDB[0] = %x ioasc = %x\n", 96889a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 96989a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)); 97089a36810SAnil Ravindranath 97189a36810SAnil Ravindranath /* Note that commands sent during reset require next command to be sent 97289a36810SAnil Ravindranath * to IOA. Hence reinit the done function as well as timeout function 97389a36810SAnil Ravindranath */ 97489a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 97589a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.request_type = REQ_TYPE_IOACMD; 97689a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.resource_handle = 97789a36810SAnil Ravindranath cpu_to_le32(PMCRAID_IOA_RES_HANDLE); 97889a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0] = PMCRAID_IOA_SHUTDOWN; 97989a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[1] = PMCRAID_SHUTDOWN_NORMAL; 98089a36810SAnil Ravindranath 98189a36810SAnil Ravindranath /* fire shutdown command to hardware. */ 98289a36810SAnil Ravindranath pmcraid_info("firing normal shutdown command (%d) to IOA\n", 98389a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle)); 98489a36810SAnil Ravindranath 985c20c4267SAnil Ravindranath pmcraid_notify_ioastate(cmd->drv_inst, PMC_DEVICE_EVENT_SHUTDOWN_START); 986c20c4267SAnil Ravindranath 987c20c4267SAnil Ravindranath pmcraid_send_cmd(cmd, pmcraid_ioa_shutdown_done, 98889a36810SAnil Ravindranath PMCRAID_SHUTDOWN_TIMEOUT, 98989a36810SAnil Ravindranath pmcraid_timeout_handler); 99089a36810SAnil Ravindranath } 99189a36810SAnil Ravindranath 99289a36810SAnil Ravindranath /** 993c20c4267SAnil Ravindranath * pmcraid_get_fwversion_done - completion function for get_fwversion 994c20c4267SAnil Ravindranath * 995c20c4267SAnil Ravindranath * @cmd: pointer to command block used to send INQUIRY command 996c20c4267SAnil Ravindranath * 997c20c4267SAnil Ravindranath * Return Value 998c20c4267SAnil Ravindranath * none 999c20c4267SAnil Ravindranath */ 1000c20c4267SAnil Ravindranath static void pmcraid_querycfg(struct pmcraid_cmd *); 1001c20c4267SAnil Ravindranath 1002c20c4267SAnil Ravindranath static void pmcraid_get_fwversion_done(struct pmcraid_cmd *cmd) 1003c20c4267SAnil Ravindranath { 1004c20c4267SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 1005c20c4267SAnil Ravindranath u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); 1006c20c4267SAnil Ravindranath unsigned long lock_flags; 1007c20c4267SAnil Ravindranath 1008c20c4267SAnil Ravindranath /* configuration table entry size depends on firmware version. If fw 1009c20c4267SAnil Ravindranath * version is not known, it is not possible to interpret IOA config 1010c20c4267SAnil Ravindranath * table 1011c20c4267SAnil Ravindranath */ 1012c20c4267SAnil Ravindranath if (ioasc) { 1013c20c4267SAnil Ravindranath pmcraid_err("IOA Inquiry failed with %x\n", ioasc); 1014c20c4267SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 1015c20c4267SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; 1016c20c4267SAnil Ravindranath pmcraid_reset_alert(cmd); 1017c20c4267SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 1018c20c4267SAnil Ravindranath } else { 1019c20c4267SAnil Ravindranath pmcraid_querycfg(cmd); 1020c20c4267SAnil Ravindranath } 1021c20c4267SAnil Ravindranath } 1022c20c4267SAnil Ravindranath 1023c20c4267SAnil Ravindranath /** 1024c20c4267SAnil Ravindranath * pmcraid_get_fwversion - reads firmware version information 1025c20c4267SAnil Ravindranath * 1026c20c4267SAnil Ravindranath * @cmd: pointer to command block used to send INQUIRY command 1027c20c4267SAnil Ravindranath * 1028c20c4267SAnil Ravindranath * Return Value 1029c20c4267SAnil Ravindranath * none 1030c20c4267SAnil Ravindranath */ 1031c20c4267SAnil Ravindranath static void pmcraid_get_fwversion(struct pmcraid_cmd *cmd) 1032c20c4267SAnil Ravindranath { 1033c20c4267SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 1034c20c4267SAnil Ravindranath struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; 1035c20c4267SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 1036c20c4267SAnil Ravindranath u16 data_size = sizeof(struct pmcraid_inquiry_data); 1037c20c4267SAnil Ravindranath 1038c20c4267SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 1039c20c4267SAnil Ravindranath ioarcb->request_type = REQ_TYPE_SCSI; 1040c20c4267SAnil Ravindranath ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); 1041c20c4267SAnil Ravindranath ioarcb->cdb[0] = INQUIRY; 1042c20c4267SAnil Ravindranath ioarcb->cdb[1] = 1; 1043c20c4267SAnil Ravindranath ioarcb->cdb[2] = 0xD0; 1044c20c4267SAnil Ravindranath ioarcb->cdb[3] = (data_size >> 8) & 0xFF; 1045c20c4267SAnil Ravindranath ioarcb->cdb[4] = data_size & 0xFF; 1046c20c4267SAnil Ravindranath 1047c20c4267SAnil Ravindranath /* Since entire inquiry data it can be part of IOARCB itself 1048c20c4267SAnil Ravindranath */ 1049c20c4267SAnil Ravindranath ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + 1050c20c4267SAnil Ravindranath offsetof(struct pmcraid_ioarcb, 1051c20c4267SAnil Ravindranath add_data.u.ioadl[0])); 1052c20c4267SAnil Ravindranath ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); 105345c80be6SArnd Bergmann ioarcb->ioarcb_bus_addr &= cpu_to_le64(~(0x1FULL)); 1054c20c4267SAnil Ravindranath 1055c20c4267SAnil Ravindranath ioarcb->request_flags0 |= NO_LINK_DESCS; 1056c20c4267SAnil Ravindranath ioarcb->data_transfer_length = cpu_to_le32(data_size); 1057c20c4267SAnil Ravindranath ioadl = &(ioarcb->add_data.u.ioadl[0]); 1058c20c4267SAnil Ravindranath ioadl->flags = IOADL_FLAGS_LAST_DESC; 1059c20c4267SAnil Ravindranath ioadl->address = cpu_to_le64(pinstance->inq_data_baddr); 1060c20c4267SAnil Ravindranath ioadl->data_len = cpu_to_le32(data_size); 1061c20c4267SAnil Ravindranath 1062c20c4267SAnil Ravindranath pmcraid_send_cmd(cmd, pmcraid_get_fwversion_done, 1063c20c4267SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler); 1064c20c4267SAnil Ravindranath } 1065c20c4267SAnil Ravindranath 1066c20c4267SAnil Ravindranath /** 106789a36810SAnil Ravindranath * pmcraid_identify_hrrq - registers host rrq buffers with IOA 106889a36810SAnil Ravindranath * @cmd: pointer to command block to be used for identify hrrq 106989a36810SAnil Ravindranath * 107089a36810SAnil Ravindranath * Return Value 1071c20c4267SAnil Ravindranath * none 107289a36810SAnil Ravindranath */ 107389a36810SAnil Ravindranath static void pmcraid_identify_hrrq(struct pmcraid_cmd *cmd) 107489a36810SAnil Ravindranath { 107589a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 107689a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 1077c20c4267SAnil Ravindranath int index = cmd->hrrq_index; 107889a36810SAnil Ravindranath __be64 hrrq_addr = cpu_to_be64(pinstance->hrrq_start_bus_addr[index]); 107945c80be6SArnd Bergmann __be32 hrrq_size = cpu_to_be32(sizeof(u32) * PMCRAID_MAX_CMD); 1080c20c4267SAnil Ravindranath void (*done_function)(struct pmcraid_cmd *); 108189a36810SAnil Ravindranath 108289a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 1083c20c4267SAnil Ravindranath cmd->hrrq_index = index + 1; 1084c20c4267SAnil Ravindranath 1085c20c4267SAnil Ravindranath if (cmd->hrrq_index < pinstance->num_hrrq) { 1086c20c4267SAnil Ravindranath done_function = pmcraid_identify_hrrq; 1087c20c4267SAnil Ravindranath } else { 1088c20c4267SAnil Ravindranath cmd->hrrq_index = 0; 1089c20c4267SAnil Ravindranath done_function = pmcraid_get_fwversion; 1090c20c4267SAnil Ravindranath } 109189a36810SAnil Ravindranath 109289a36810SAnil Ravindranath /* Initialize ioarcb */ 109389a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_IOACMD; 109489a36810SAnil Ravindranath ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); 109589a36810SAnil Ravindranath 109689a36810SAnil Ravindranath /* initialize the hrrq number where IOA will respond to this command */ 109789a36810SAnil Ravindranath ioarcb->hrrq_id = index; 109889a36810SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_IDENTIFY_HRRQ; 109989a36810SAnil Ravindranath ioarcb->cdb[1] = index; 110089a36810SAnil Ravindranath 110189a36810SAnil Ravindranath /* IOA expects 64-bit pci address to be written in B.E format 110289a36810SAnil Ravindranath * (i.e cdb[2]=MSByte..cdb[9]=LSB. 110389a36810SAnil Ravindranath */ 1104c20c4267SAnil Ravindranath pmcraid_info("HRRQ_IDENTIFY with hrrq:ioarcb:index => %llx:%llx:%x\n", 1105c20c4267SAnil Ravindranath hrrq_addr, ioarcb->ioarcb_bus_addr, index); 110689a36810SAnil Ravindranath 110789a36810SAnil Ravindranath memcpy(&(ioarcb->cdb[2]), &hrrq_addr, sizeof(hrrq_addr)); 110889a36810SAnil Ravindranath memcpy(&(ioarcb->cdb[10]), &hrrq_size, sizeof(hrrq_size)); 110989a36810SAnil Ravindranath 111089a36810SAnil Ravindranath /* Subsequent commands require HRRQ identification to be successful. 111189a36810SAnil Ravindranath * Note that this gets called even during reset from SCSI mid-layer 111289a36810SAnil Ravindranath * or tasklet 111389a36810SAnil Ravindranath */ 1114c20c4267SAnil Ravindranath pmcraid_send_cmd(cmd, done_function, 111589a36810SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, 111689a36810SAnil Ravindranath pmcraid_timeout_handler); 111789a36810SAnil Ravindranath } 111889a36810SAnil Ravindranath 111989a36810SAnil Ravindranath static void pmcraid_process_ccn(struct pmcraid_cmd *cmd); 112089a36810SAnil Ravindranath static void pmcraid_process_ldn(struct pmcraid_cmd *cmd); 112189a36810SAnil Ravindranath 112289a36810SAnil Ravindranath /** 112389a36810SAnil Ravindranath * pmcraid_send_hcam_cmd - send an initialized command block(HCAM) to IOA 112489a36810SAnil Ravindranath * 112589a36810SAnil Ravindranath * @cmd: initialized command block pointer 112689a36810SAnil Ravindranath * 112789a36810SAnil Ravindranath * Return Value 112889a36810SAnil Ravindranath * none 112989a36810SAnil Ravindranath */ 113089a36810SAnil Ravindranath static void pmcraid_send_hcam_cmd(struct pmcraid_cmd *cmd) 113189a36810SAnil Ravindranath { 113289a36810SAnil Ravindranath if (cmd->ioa_cb->ioarcb.cdb[1] == PMCRAID_HCAM_CODE_CONFIG_CHANGE) 113389a36810SAnil Ravindranath atomic_set(&(cmd->drv_inst->ccn.ignore), 0); 113489a36810SAnil Ravindranath else 113589a36810SAnil Ravindranath atomic_set(&(cmd->drv_inst->ldn.ignore), 0); 113689a36810SAnil Ravindranath 113789a36810SAnil Ravindranath pmcraid_send_cmd(cmd, cmd->cmd_done, 0, NULL); 113889a36810SAnil Ravindranath } 113989a36810SAnil Ravindranath 114089a36810SAnil Ravindranath /** 114189a36810SAnil Ravindranath * pmcraid_init_hcam - send an initialized command block(HCAM) to IOA 114289a36810SAnil Ravindranath * 114389a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 114489a36810SAnil Ravindranath * @type: HCAM type 114589a36810SAnil Ravindranath * 114689a36810SAnil Ravindranath * Return Value 114789a36810SAnil Ravindranath * pointer to initialized pmcraid_cmd structure or NULL 114889a36810SAnil Ravindranath */ 114989a36810SAnil Ravindranath static struct pmcraid_cmd *pmcraid_init_hcam 115089a36810SAnil Ravindranath ( 115189a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 115289a36810SAnil Ravindranath u8 type 115389a36810SAnil Ravindranath ) 115489a36810SAnil Ravindranath { 115589a36810SAnil Ravindranath struct pmcraid_cmd *cmd; 115689a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb; 115789a36810SAnil Ravindranath struct pmcraid_ioadl_desc *ioadl; 115889a36810SAnil Ravindranath struct pmcraid_hostrcb *hcam; 115989a36810SAnil Ravindranath void (*cmd_done) (struct pmcraid_cmd *); 116089a36810SAnil Ravindranath dma_addr_t dma; 116189a36810SAnil Ravindranath int rcb_size; 116289a36810SAnil Ravindranath 116389a36810SAnil Ravindranath cmd = pmcraid_get_free_cmd(pinstance); 116489a36810SAnil Ravindranath 116589a36810SAnil Ravindranath if (!cmd) { 116689a36810SAnil Ravindranath pmcraid_err("no free command blocks for hcam\n"); 116789a36810SAnil Ravindranath return cmd; 116889a36810SAnil Ravindranath } 116989a36810SAnil Ravindranath 117089a36810SAnil Ravindranath if (type == PMCRAID_HCAM_CODE_CONFIG_CHANGE) { 1171c20c4267SAnil Ravindranath rcb_size = sizeof(struct pmcraid_hcam_ccn_ext); 117289a36810SAnil Ravindranath cmd_done = pmcraid_process_ccn; 117389a36810SAnil Ravindranath dma = pinstance->ccn.baddr + PMCRAID_AEN_HDR_SIZE; 117489a36810SAnil Ravindranath hcam = &pinstance->ccn; 117589a36810SAnil Ravindranath } else { 117689a36810SAnil Ravindranath rcb_size = sizeof(struct pmcraid_hcam_ldn); 117789a36810SAnil Ravindranath cmd_done = pmcraid_process_ldn; 117889a36810SAnil Ravindranath dma = pinstance->ldn.baddr + PMCRAID_AEN_HDR_SIZE; 117989a36810SAnil Ravindranath hcam = &pinstance->ldn; 118089a36810SAnil Ravindranath } 118189a36810SAnil Ravindranath 118289a36810SAnil Ravindranath /* initialize command pointer used for HCAM registration */ 118389a36810SAnil Ravindranath hcam->cmd = cmd; 118489a36810SAnil Ravindranath 118589a36810SAnil Ravindranath ioarcb = &cmd->ioa_cb->ioarcb; 118689a36810SAnil Ravindranath ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + 118789a36810SAnil Ravindranath offsetof(struct pmcraid_ioarcb, 118889a36810SAnil Ravindranath add_data.u.ioadl[0])); 118989a36810SAnil Ravindranath ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); 119089a36810SAnil Ravindranath ioadl = ioarcb->add_data.u.ioadl; 119189a36810SAnil Ravindranath 119289a36810SAnil Ravindranath /* Initialize ioarcb */ 119389a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_HCAM; 119489a36810SAnil Ravindranath ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); 119589a36810SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_HOST_CONTROLLED_ASYNC; 119689a36810SAnil Ravindranath ioarcb->cdb[1] = type; 119789a36810SAnil Ravindranath ioarcb->cdb[7] = (rcb_size >> 8) & 0xFF; 119889a36810SAnil Ravindranath ioarcb->cdb[8] = (rcb_size) & 0xFF; 119989a36810SAnil Ravindranath 120089a36810SAnil Ravindranath ioarcb->data_transfer_length = cpu_to_le32(rcb_size); 120189a36810SAnil Ravindranath 120288197966SAnil Ravindranath ioadl[0].flags |= IOADL_FLAGS_READ_LAST; 120389a36810SAnil Ravindranath ioadl[0].data_len = cpu_to_le32(rcb_size); 120445c80be6SArnd Bergmann ioadl[0].address = cpu_to_le64(dma); 120589a36810SAnil Ravindranath 120689a36810SAnil Ravindranath cmd->cmd_done = cmd_done; 120789a36810SAnil Ravindranath return cmd; 120889a36810SAnil Ravindranath } 120989a36810SAnil Ravindranath 121089a36810SAnil Ravindranath /** 121189a36810SAnil Ravindranath * pmcraid_send_hcam - Send an HCAM to IOA 121289a36810SAnil Ravindranath * @pinstance: ioa config struct 121389a36810SAnil Ravindranath * @type: HCAM type 121489a36810SAnil Ravindranath * 121589a36810SAnil Ravindranath * This function will send a Host Controlled Async command to IOA. 121689a36810SAnil Ravindranath * 121789a36810SAnil Ravindranath * Return value: 121889a36810SAnil Ravindranath * none 121989a36810SAnil Ravindranath */ 122089a36810SAnil Ravindranath static void pmcraid_send_hcam(struct pmcraid_instance *pinstance, u8 type) 122189a36810SAnil Ravindranath { 122289a36810SAnil Ravindranath struct pmcraid_cmd *cmd = pmcraid_init_hcam(pinstance, type); 122389a36810SAnil Ravindranath pmcraid_send_hcam_cmd(cmd); 122489a36810SAnil Ravindranath } 122589a36810SAnil Ravindranath 122689a36810SAnil Ravindranath 122789a36810SAnil Ravindranath /** 122889a36810SAnil Ravindranath * pmcraid_prepare_cancel_cmd - prepares a command block to abort another 122989a36810SAnil Ravindranath * 123089a36810SAnil Ravindranath * @cmd: pointer to cmd that is used as cancelling command 123189a36810SAnil Ravindranath * @cmd_to_cancel: pointer to the command that needs to be cancelled 123289a36810SAnil Ravindranath */ 123389a36810SAnil Ravindranath static void pmcraid_prepare_cancel_cmd( 123489a36810SAnil Ravindranath struct pmcraid_cmd *cmd, 123589a36810SAnil Ravindranath struct pmcraid_cmd *cmd_to_cancel 123689a36810SAnil Ravindranath ) 123789a36810SAnil Ravindranath { 123889a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 123945c80be6SArnd Bergmann __be64 ioarcb_addr; 124045c80be6SArnd Bergmann 124145c80be6SArnd Bergmann /* IOARCB address of the command to be cancelled is given in 124245c80be6SArnd Bergmann * cdb[2]..cdb[9] is Big-Endian format. Note that length bits in 124345c80be6SArnd Bergmann * IOARCB address are not masked. 124445c80be6SArnd Bergmann */ 124545c80be6SArnd Bergmann ioarcb_addr = cpu_to_be64(le64_to_cpu(cmd_to_cancel->ioa_cb->ioarcb.ioarcb_bus_addr)); 124689a36810SAnil Ravindranath 124789a36810SAnil Ravindranath /* Get the resource handle to where the command to be aborted has been 124889a36810SAnil Ravindranath * sent. 124989a36810SAnil Ravindranath */ 125089a36810SAnil Ravindranath ioarcb->resource_handle = cmd_to_cancel->ioa_cb->ioarcb.resource_handle; 125189a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_IOACMD; 125289a36810SAnil Ravindranath memset(ioarcb->cdb, 0, PMCRAID_MAX_CDB_LEN); 125389a36810SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_ABORT_CMD; 125489a36810SAnil Ravindranath 125589a36810SAnil Ravindranath memcpy(&(ioarcb->cdb[2]), &ioarcb_addr, sizeof(ioarcb_addr)); 125689a36810SAnil Ravindranath } 125789a36810SAnil Ravindranath 125889a36810SAnil Ravindranath /** 125989a36810SAnil Ravindranath * pmcraid_cancel_hcam - sends ABORT task to abort a given HCAM 126089a36810SAnil Ravindranath * 126189a36810SAnil Ravindranath * @cmd: command to be used as cancelling command 126289a36810SAnil Ravindranath * @type: HCAM type 126389a36810SAnil Ravindranath * @cmd_done: op done function for the cancelling command 126489a36810SAnil Ravindranath */ 126589a36810SAnil Ravindranath static void pmcraid_cancel_hcam( 126689a36810SAnil Ravindranath struct pmcraid_cmd *cmd, 126789a36810SAnil Ravindranath u8 type, 126889a36810SAnil Ravindranath void (*cmd_done) (struct pmcraid_cmd *) 126989a36810SAnil Ravindranath ) 127089a36810SAnil Ravindranath { 127189a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 127289a36810SAnil Ravindranath struct pmcraid_hostrcb *hcam; 127389a36810SAnil Ravindranath 127489a36810SAnil Ravindranath pinstance = cmd->drv_inst; 127589a36810SAnil Ravindranath hcam = (type == PMCRAID_HCAM_CODE_LOG_DATA) ? 127689a36810SAnil Ravindranath &pinstance->ldn : &pinstance->ccn; 127789a36810SAnil Ravindranath 127889a36810SAnil Ravindranath /* prepare for cancelling previous hcam command. If the HCAM is 127989a36810SAnil Ravindranath * currently not pending with IOA, we would have hcam->cmd as non-null 128089a36810SAnil Ravindranath */ 128189a36810SAnil Ravindranath if (hcam->cmd == NULL) 128289a36810SAnil Ravindranath return; 128389a36810SAnil Ravindranath 128489a36810SAnil Ravindranath pmcraid_prepare_cancel_cmd(cmd, hcam->cmd); 128589a36810SAnil Ravindranath 128689a36810SAnil Ravindranath /* writing to IOARRIN must be protected by host_lock, as mid-layer 128789a36810SAnil Ravindranath * schedule queuecommand while we are doing this 128889a36810SAnil Ravindranath */ 128989a36810SAnil Ravindranath pmcraid_send_cmd(cmd, cmd_done, 129089a36810SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, 129189a36810SAnil Ravindranath pmcraid_timeout_handler); 129289a36810SAnil Ravindranath } 129389a36810SAnil Ravindranath 129489a36810SAnil Ravindranath /** 129589a36810SAnil Ravindranath * pmcraid_cancel_ccn - cancel CCN HCAM already registered with IOA 129689a36810SAnil Ravindranath * 129789a36810SAnil Ravindranath * @cmd: command block to be used for cancelling the HCAM 129889a36810SAnil Ravindranath */ 129989a36810SAnil Ravindranath static void pmcraid_cancel_ccn(struct pmcraid_cmd *cmd) 130089a36810SAnil Ravindranath { 130189a36810SAnil Ravindranath pmcraid_info("response for Cancel LDN CDB[0] = %x ioasc = %x\n", 130289a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 130389a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)); 130489a36810SAnil Ravindranath 130589a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 130689a36810SAnil Ravindranath 130789a36810SAnil Ravindranath pmcraid_cancel_hcam(cmd, 130889a36810SAnil Ravindranath PMCRAID_HCAM_CODE_CONFIG_CHANGE, 130989a36810SAnil Ravindranath pmcraid_ioa_shutdown); 131089a36810SAnil Ravindranath } 131189a36810SAnil Ravindranath 131289a36810SAnil Ravindranath /** 131389a36810SAnil Ravindranath * pmcraid_cancel_ldn - cancel LDN HCAM already registered with IOA 131489a36810SAnil Ravindranath * 131589a36810SAnil Ravindranath * @cmd: command block to be used for cancelling the HCAM 131689a36810SAnil Ravindranath */ 131789a36810SAnil Ravindranath static void pmcraid_cancel_ldn(struct pmcraid_cmd *cmd) 131889a36810SAnil Ravindranath { 131989a36810SAnil Ravindranath pmcraid_cancel_hcam(cmd, 132089a36810SAnil Ravindranath PMCRAID_HCAM_CODE_LOG_DATA, 132189a36810SAnil Ravindranath pmcraid_cancel_ccn); 132289a36810SAnil Ravindranath } 132389a36810SAnil Ravindranath 132489a36810SAnil Ravindranath /** 132589a36810SAnil Ravindranath * pmcraid_expose_resource - check if the resource can be exposed to OS 132689a36810SAnil Ravindranath * 1327c20c4267SAnil Ravindranath * @fw_version: firmware version code 132889a36810SAnil Ravindranath * @cfgte: pointer to configuration table entry of the resource 132989a36810SAnil Ravindranath * 133089a36810SAnil Ravindranath * Return value: 133189a36810SAnil Ravindranath * true if resource can be added to midlayer, false(0) otherwise 133289a36810SAnil Ravindranath */ 1333c20c4267SAnil Ravindranath static int pmcraid_expose_resource(u16 fw_version, 1334c20c4267SAnil Ravindranath struct pmcraid_config_table_entry *cfgte) 133589a36810SAnil Ravindranath { 133689a36810SAnil Ravindranath int retval = 0; 133789a36810SAnil Ravindranath 1338c20c4267SAnil Ravindranath if (cfgte->resource_type == RES_TYPE_VSET) { 1339c20c4267SAnil Ravindranath if (fw_version <= PMCRAID_FW_VERSION_1) 1340729c8456SAnil Ravindranath retval = ((cfgte->unique_flags1 & 0x80) == 0); 1341c20c4267SAnil Ravindranath else 1342c20c4267SAnil Ravindranath retval = ((cfgte->unique_flags0 & 0x80) == 0 && 1343c20c4267SAnil Ravindranath (cfgte->unique_flags1 & 0x80) == 0); 1344c20c4267SAnil Ravindranath 1345c20c4267SAnil Ravindranath } else if (cfgte->resource_type == RES_TYPE_GSCSI) 134689a36810SAnil Ravindranath retval = (RES_BUS(cfgte->resource_address) != 134789a36810SAnil Ravindranath PMCRAID_VIRTUAL_ENCL_BUS_ID); 134889a36810SAnil Ravindranath return retval; 134989a36810SAnil Ravindranath } 135089a36810SAnil Ravindranath 135189a36810SAnil Ravindranath /* attributes supported by pmcraid_event_family */ 135289a36810SAnil Ravindranath enum { 135389a36810SAnil Ravindranath PMCRAID_AEN_ATTR_UNSPEC, 135489a36810SAnil Ravindranath PMCRAID_AEN_ATTR_EVENT, 135589a36810SAnil Ravindranath __PMCRAID_AEN_ATTR_MAX, 135689a36810SAnil Ravindranath }; 135789a36810SAnil Ravindranath #define PMCRAID_AEN_ATTR_MAX (__PMCRAID_AEN_ATTR_MAX - 1) 135889a36810SAnil Ravindranath 135989a36810SAnil Ravindranath /* commands supported by pmcraid_event_family */ 136089a36810SAnil Ravindranath enum { 136189a36810SAnil Ravindranath PMCRAID_AEN_CMD_UNSPEC, 136289a36810SAnil Ravindranath PMCRAID_AEN_CMD_EVENT, 136389a36810SAnil Ravindranath __PMCRAID_AEN_CMD_MAX, 136489a36810SAnil Ravindranath }; 136589a36810SAnil Ravindranath #define PMCRAID_AEN_CMD_MAX (__PMCRAID_AEN_CMD_MAX - 1) 136689a36810SAnil Ravindranath 13675e53e689SJohannes Berg static struct genl_multicast_group pmcraid_mcgrps[] = { 13685e53e689SJohannes Berg { .name = "events", /* not really used - see ID discussion below */ }, 13695e53e689SJohannes Berg }; 13705e53e689SJohannes Berg 137156989f6dSJohannes Berg static struct genl_family pmcraid_event_family __ro_after_init = { 1372489111e5SJohannes Berg .module = THIS_MODULE, 137389a36810SAnil Ravindranath .name = "pmcraid", 137489a36810SAnil Ravindranath .version = 1, 13755e53e689SJohannes Berg .maxattr = PMCRAID_AEN_ATTR_MAX, 13765e53e689SJohannes Berg .mcgrps = pmcraid_mcgrps, 13775e53e689SJohannes Berg .n_mcgrps = ARRAY_SIZE(pmcraid_mcgrps), 137889a36810SAnil Ravindranath }; 137989a36810SAnil Ravindranath 138089a36810SAnil Ravindranath /** 138189a36810SAnil Ravindranath * pmcraid_netlink_init - registers pmcraid_event_family 138289a36810SAnil Ravindranath * 138389a36810SAnil Ravindranath * Return value: 138489a36810SAnil Ravindranath * 0 if the pmcraid_event_family is successfully registered 138589a36810SAnil Ravindranath * with netlink generic, non-zero otherwise 138689a36810SAnil Ravindranath */ 138756989f6dSJohannes Berg static int __init pmcraid_netlink_init(void) 138889a36810SAnil Ravindranath { 138989a36810SAnil Ravindranath int result; 139089a36810SAnil Ravindranath 139189a36810SAnil Ravindranath result = genl_register_family(&pmcraid_event_family); 139289a36810SAnil Ravindranath 139389a36810SAnil Ravindranath if (result) 139489a36810SAnil Ravindranath return result; 139589a36810SAnil Ravindranath 139689a36810SAnil Ravindranath pmcraid_info("registered NETLINK GENERIC group: %d\n", 139789a36810SAnil Ravindranath pmcraid_event_family.id); 139889a36810SAnil Ravindranath 139989a36810SAnil Ravindranath return result; 140089a36810SAnil Ravindranath } 140189a36810SAnil Ravindranath 140289a36810SAnil Ravindranath /** 140389a36810SAnil Ravindranath * pmcraid_netlink_release - unregisters pmcraid_event_family 140489a36810SAnil Ravindranath * 140589a36810SAnil Ravindranath * Return value: 140689a36810SAnil Ravindranath * none 140789a36810SAnil Ravindranath */ 140889a36810SAnil Ravindranath static void pmcraid_netlink_release(void) 140989a36810SAnil Ravindranath { 141089a36810SAnil Ravindranath genl_unregister_family(&pmcraid_event_family); 141189a36810SAnil Ravindranath } 141289a36810SAnil Ravindranath 141389a36810SAnil Ravindranath /** 141489a36810SAnil Ravindranath * pmcraid_notify_aen - sends event msg to user space application 141589a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 141689a36810SAnil Ravindranath * @type: HCAM type 141789a36810SAnil Ravindranath * 141889a36810SAnil Ravindranath * Return value: 141989a36810SAnil Ravindranath * 0 if success, error value in case of any failure. 142089a36810SAnil Ravindranath */ 1421c20c4267SAnil Ravindranath static int pmcraid_notify_aen( 1422c20c4267SAnil Ravindranath struct pmcraid_instance *pinstance, 1423c20c4267SAnil Ravindranath struct pmcraid_aen_msg *aen_msg, 1424c20c4267SAnil Ravindranath u32 data_size 1425c20c4267SAnil Ravindranath ) 142689a36810SAnil Ravindranath { 142789a36810SAnil Ravindranath struct sk_buff *skb; 142889a36810SAnil Ravindranath void *msg_header; 1429c20c4267SAnil Ravindranath u32 total_size, nla_genl_hdr_total_size; 143089a36810SAnil Ravindranath int result; 143189a36810SAnil Ravindranath 143289a36810SAnil Ravindranath aen_msg->hostno = (pinstance->host->unique_id << 16 | 143389a36810SAnil Ravindranath MINOR(pinstance->cdev.dev)); 143489a36810SAnil Ravindranath aen_msg->length = data_size; 1435c20c4267SAnil Ravindranath 143689a36810SAnil Ravindranath data_size += sizeof(*aen_msg); 143789a36810SAnil Ravindranath 143889a36810SAnil Ravindranath total_size = nla_total_size(data_size); 1439c20c4267SAnil Ravindranath /* Add GENL_HDR to total_size */ 1440c20c4267SAnil Ravindranath nla_genl_hdr_total_size = 1441c20c4267SAnil Ravindranath (total_size + (GENL_HDRLEN + 1442c20c4267SAnil Ravindranath ((struct genl_family *)&pmcraid_event_family)->hdrsize) 1443c20c4267SAnil Ravindranath + NLMSG_HDRLEN); 1444c20c4267SAnil Ravindranath skb = genlmsg_new(nla_genl_hdr_total_size, GFP_ATOMIC); 144589a36810SAnil Ravindranath 144689a36810SAnil Ravindranath 144789a36810SAnil Ravindranath if (!skb) { 144889a36810SAnil Ravindranath pmcraid_err("Failed to allocate aen data SKB of size: %x\n", 144989a36810SAnil Ravindranath total_size); 145089a36810SAnil Ravindranath return -ENOMEM; 145189a36810SAnil Ravindranath } 145289a36810SAnil Ravindranath 145389a36810SAnil Ravindranath /* add the genetlink message header */ 145489a36810SAnil Ravindranath msg_header = genlmsg_put(skb, 0, 0, 145589a36810SAnil Ravindranath &pmcraid_event_family, 0, 145689a36810SAnil Ravindranath PMCRAID_AEN_CMD_EVENT); 145789a36810SAnil Ravindranath if (!msg_header) { 145889a36810SAnil Ravindranath pmcraid_err("failed to copy command details\n"); 145989a36810SAnil Ravindranath nlmsg_free(skb); 146089a36810SAnil Ravindranath return -ENOMEM; 146189a36810SAnil Ravindranath } 146289a36810SAnil Ravindranath 146389a36810SAnil Ravindranath result = nla_put(skb, PMCRAID_AEN_ATTR_EVENT, data_size, aen_msg); 146489a36810SAnil Ravindranath 146589a36810SAnil Ravindranath if (result) { 146689a36810SAnil Ravindranath pmcraid_err("failed to copy AEN attribute data\n"); 146789a36810SAnil Ravindranath nlmsg_free(skb); 146889a36810SAnil Ravindranath return -EINVAL; 146989a36810SAnil Ravindranath } 147089a36810SAnil Ravindranath 147189a36810SAnil Ravindranath /* send genetlink multicast message to notify appplications */ 1472053c095aSJohannes Berg genlmsg_end(skb, msg_header); 147389a36810SAnil Ravindranath 14745e53e689SJohannes Berg result = genlmsg_multicast(&pmcraid_event_family, skb, 14755e53e689SJohannes Berg 0, 0, GFP_ATOMIC); 147689a36810SAnil Ravindranath 147789a36810SAnil Ravindranath /* If there are no listeners, genlmsg_multicast may return non-zero 147889a36810SAnil Ravindranath * value. 147989a36810SAnil Ravindranath */ 148089a36810SAnil Ravindranath if (result) 1481c20c4267SAnil Ravindranath pmcraid_info("error (%x) sending aen event message\n", result); 148289a36810SAnil Ravindranath return result; 148389a36810SAnil Ravindranath } 148489a36810SAnil Ravindranath 148589a36810SAnil Ravindranath /** 1486c20c4267SAnil Ravindranath * pmcraid_notify_ccn - notifies about CCN event msg to user space 1487c20c4267SAnil Ravindranath * @pinstance: pointer adapter instance structure 1488c20c4267SAnil Ravindranath * 1489c20c4267SAnil Ravindranath * Return value: 1490c20c4267SAnil Ravindranath * 0 if success, error value in case of any failure 1491c20c4267SAnil Ravindranath */ 1492c20c4267SAnil Ravindranath static int pmcraid_notify_ccn(struct pmcraid_instance *pinstance) 1493c20c4267SAnil Ravindranath { 1494c20c4267SAnil Ravindranath return pmcraid_notify_aen(pinstance, 1495c20c4267SAnil Ravindranath pinstance->ccn.msg, 149645c80be6SArnd Bergmann le32_to_cpu(pinstance->ccn.hcam->data_len) + 1497c20c4267SAnil Ravindranath sizeof(struct pmcraid_hcam_hdr)); 1498c20c4267SAnil Ravindranath } 1499c20c4267SAnil Ravindranath 1500c20c4267SAnil Ravindranath /** 1501c20c4267SAnil Ravindranath * pmcraid_notify_ldn - notifies about CCN event msg to user space 1502c20c4267SAnil Ravindranath * @pinstance: pointer adapter instance structure 1503c20c4267SAnil Ravindranath * 1504c20c4267SAnil Ravindranath * Return value: 1505c20c4267SAnil Ravindranath * 0 if success, error value in case of any failure 1506c20c4267SAnil Ravindranath */ 1507c20c4267SAnil Ravindranath static int pmcraid_notify_ldn(struct pmcraid_instance *pinstance) 1508c20c4267SAnil Ravindranath { 1509c20c4267SAnil Ravindranath return pmcraid_notify_aen(pinstance, 1510c20c4267SAnil Ravindranath pinstance->ldn.msg, 151145c80be6SArnd Bergmann le32_to_cpu(pinstance->ldn.hcam->data_len) + 1512c20c4267SAnil Ravindranath sizeof(struct pmcraid_hcam_hdr)); 1513c20c4267SAnil Ravindranath } 1514c20c4267SAnil Ravindranath 1515c20c4267SAnil Ravindranath /** 1516c20c4267SAnil Ravindranath * pmcraid_notify_ioastate - sends IOA state event msg to user space 1517c20c4267SAnil Ravindranath * @pinstance: pointer adapter instance structure 1518c20c4267SAnil Ravindranath * @evt: controller state event to be sent 1519c20c4267SAnil Ravindranath * 1520c20c4267SAnil Ravindranath * Return value: 1521c20c4267SAnil Ravindranath * 0 if success, error value in case of any failure 1522c20c4267SAnil Ravindranath */ 1523c20c4267SAnil Ravindranath static void pmcraid_notify_ioastate(struct pmcraid_instance *pinstance, u32 evt) 1524c20c4267SAnil Ravindranath { 1525c20c4267SAnil Ravindranath pinstance->scn.ioa_state = evt; 1526c20c4267SAnil Ravindranath pmcraid_notify_aen(pinstance, 1527c20c4267SAnil Ravindranath &pinstance->scn.msg, 1528c20c4267SAnil Ravindranath sizeof(u32)); 1529c20c4267SAnil Ravindranath } 1530c20c4267SAnil Ravindranath 1531c20c4267SAnil Ravindranath /** 153289a36810SAnil Ravindranath * pmcraid_handle_config_change - Handle a config change from the adapter 153389a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 153489a36810SAnil Ravindranath * 153589a36810SAnil Ravindranath * Return value: 153689a36810SAnil Ravindranath * none 153789a36810SAnil Ravindranath */ 1538729c8456SAnil Ravindranath 153989a36810SAnil Ravindranath static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance) 154089a36810SAnil Ravindranath { 154189a36810SAnil Ravindranath struct pmcraid_config_table_entry *cfg_entry; 154289a36810SAnil Ravindranath struct pmcraid_hcam_ccn *ccn_hcam; 154389a36810SAnil Ravindranath struct pmcraid_cmd *cmd; 154489a36810SAnil Ravindranath struct pmcraid_cmd *cfgcmd; 154589a36810SAnil Ravindranath struct pmcraid_resource_entry *res = NULL; 154689a36810SAnil Ravindranath unsigned long lock_flags; 154789a36810SAnil Ravindranath unsigned long host_lock_flags; 1548729c8456SAnil Ravindranath u32 new_entry = 1; 1549729c8456SAnil Ravindranath u32 hidden_entry = 0; 1550c20c4267SAnil Ravindranath u16 fw_version; 155189a36810SAnil Ravindranath int rc; 155289a36810SAnil Ravindranath 155389a36810SAnil Ravindranath ccn_hcam = (struct pmcraid_hcam_ccn *)pinstance->ccn.hcam; 155489a36810SAnil Ravindranath cfg_entry = &ccn_hcam->cfg_entry; 1555c20c4267SAnil Ravindranath fw_version = be16_to_cpu(pinstance->inq_data->fw_version); 155689a36810SAnil Ravindranath 1557592488a3SAnil Ravindranath pmcraid_info("CCN(%x): %x timestamp: %llx type: %x lost: %x flags: %x \ 1558592488a3SAnil Ravindranath res: %x:%x:%x:%x\n", 155945c80be6SArnd Bergmann le32_to_cpu(pinstance->ccn.hcam->ilid), 156089a36810SAnil Ravindranath pinstance->ccn.hcam->op_code, 156145c80be6SArnd Bergmann (le32_to_cpu(pinstance->ccn.hcam->timestamp1) | 156245c80be6SArnd Bergmann ((le32_to_cpu(pinstance->ccn.hcam->timestamp2) & 0xffffffffLL) << 32)), 156389a36810SAnil Ravindranath pinstance->ccn.hcam->notification_type, 156489a36810SAnil Ravindranath pinstance->ccn.hcam->notification_lost, 156589a36810SAnil Ravindranath pinstance->ccn.hcam->flags, 156689a36810SAnil Ravindranath pinstance->host->unique_id, 156789a36810SAnil Ravindranath RES_IS_VSET(*cfg_entry) ? PMCRAID_VSET_BUS_ID : 156889a36810SAnil Ravindranath (RES_IS_GSCSI(*cfg_entry) ? PMCRAID_PHYS_BUS_ID : 156989a36810SAnil Ravindranath RES_BUS(cfg_entry->resource_address)), 1570c20c4267SAnil Ravindranath RES_IS_VSET(*cfg_entry) ? 1571c20c4267SAnil Ravindranath (fw_version <= PMCRAID_FW_VERSION_1 ? 1572c20c4267SAnil Ravindranath cfg_entry->unique_flags1 : 157345c80be6SArnd Bergmann le16_to_cpu(cfg_entry->array_id) & 0xFF) : 157489a36810SAnil Ravindranath RES_TARGET(cfg_entry->resource_address), 157589a36810SAnil Ravindranath RES_LUN(cfg_entry->resource_address)); 157689a36810SAnil Ravindranath 157789a36810SAnil Ravindranath 157889a36810SAnil Ravindranath /* If this HCAM indicates a lost notification, read the config table */ 157989a36810SAnil Ravindranath if (pinstance->ccn.hcam->notification_lost) { 158089a36810SAnil Ravindranath cfgcmd = pmcraid_get_free_cmd(pinstance); 158189a36810SAnil Ravindranath if (cfgcmd) { 158289a36810SAnil Ravindranath pmcraid_info("lost CCN, reading config table\b"); 158389a36810SAnil Ravindranath pinstance->reinit_cfg_table = 1; 158489a36810SAnil Ravindranath pmcraid_querycfg(cfgcmd); 158589a36810SAnil Ravindranath } else { 158689a36810SAnil Ravindranath pmcraid_err("lost CCN, no free cmd for querycfg\n"); 158789a36810SAnil Ravindranath } 158889a36810SAnil Ravindranath goto out_notify_apps; 158989a36810SAnil Ravindranath } 159089a36810SAnil Ravindranath 159189a36810SAnil Ravindranath /* If this resource is not going to be added to mid-layer, just notify 1592729c8456SAnil Ravindranath * applications and return. If this notification is about hiding a VSET 1593729c8456SAnil Ravindranath * resource, check if it was exposed already. 159489a36810SAnil Ravindranath */ 1595729c8456SAnil Ravindranath if (pinstance->ccn.hcam->notification_type == 1596729c8456SAnil Ravindranath NOTIFICATION_TYPE_ENTRY_CHANGED && 1597c20c4267SAnil Ravindranath cfg_entry->resource_type == RES_TYPE_VSET) { 1598c20c4267SAnil Ravindranath 1599c20c4267SAnil Ravindranath if (fw_version <= PMCRAID_FW_VERSION_1) 1600c20c4267SAnil Ravindranath hidden_entry = (cfg_entry->unique_flags1 & 0x80) != 0; 1601c20c4267SAnil Ravindranath else 1602c20c4267SAnil Ravindranath hidden_entry = (cfg_entry->unique_flags1 & 0x80) != 0; 1603c20c4267SAnil Ravindranath 1604c20c4267SAnil Ravindranath } else if (!pmcraid_expose_resource(fw_version, cfg_entry)) { 160589a36810SAnil Ravindranath goto out_notify_apps; 1606c20c4267SAnil Ravindranath } 160789a36810SAnil Ravindranath 160889a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->resource_lock, lock_flags); 160989a36810SAnil Ravindranath list_for_each_entry(res, &pinstance->used_res_q, queue) { 161089a36810SAnil Ravindranath rc = memcmp(&res->cfg_entry.resource_address, 161189a36810SAnil Ravindranath &cfg_entry->resource_address, 161289a36810SAnil Ravindranath sizeof(cfg_entry->resource_address)); 161389a36810SAnil Ravindranath if (!rc) { 161489a36810SAnil Ravindranath new_entry = 0; 161589a36810SAnil Ravindranath break; 161689a36810SAnil Ravindranath } 161789a36810SAnil Ravindranath } 161889a36810SAnil Ravindranath 161989a36810SAnil Ravindranath if (new_entry) { 162089a36810SAnil Ravindranath 1621729c8456SAnil Ravindranath if (hidden_entry) { 1622729c8456SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, 1623729c8456SAnil Ravindranath lock_flags); 1624729c8456SAnil Ravindranath goto out_notify_apps; 1625729c8456SAnil Ravindranath } 1626729c8456SAnil Ravindranath 162789a36810SAnil Ravindranath /* If there are more number of resources than what driver can 162889a36810SAnil Ravindranath * manage, do not notify the applications about the CCN. Just 162989a36810SAnil Ravindranath * ignore this notifications and re-register the same HCAM 163089a36810SAnil Ravindranath */ 163189a36810SAnil Ravindranath if (list_empty(&pinstance->free_res_q)) { 163289a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, 163389a36810SAnil Ravindranath lock_flags); 163489a36810SAnil Ravindranath pmcraid_err("too many resources attached\n"); 163589a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, 163689a36810SAnil Ravindranath host_lock_flags); 163789a36810SAnil Ravindranath pmcraid_send_hcam(pinstance, 163889a36810SAnil Ravindranath PMCRAID_HCAM_CODE_CONFIG_CHANGE); 163989a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 164089a36810SAnil Ravindranath host_lock_flags); 164189a36810SAnil Ravindranath return; 164289a36810SAnil Ravindranath } 164389a36810SAnil Ravindranath 164489a36810SAnil Ravindranath res = list_entry(pinstance->free_res_q.next, 164589a36810SAnil Ravindranath struct pmcraid_resource_entry, queue); 164689a36810SAnil Ravindranath 164789a36810SAnil Ravindranath list_del(&res->queue); 164889a36810SAnil Ravindranath res->scsi_dev = NULL; 164989a36810SAnil Ravindranath res->reset_progress = 0; 165089a36810SAnil Ravindranath list_add_tail(&res->queue, &pinstance->used_res_q); 165189a36810SAnil Ravindranath } 165289a36810SAnil Ravindranath 1653c20c4267SAnil Ravindranath memcpy(&res->cfg_entry, cfg_entry, pinstance->config_table_entry_size); 165489a36810SAnil Ravindranath 165589a36810SAnil Ravindranath if (pinstance->ccn.hcam->notification_type == 1656729c8456SAnil Ravindranath NOTIFICATION_TYPE_ENTRY_DELETED || hidden_entry) { 165789a36810SAnil Ravindranath if (res->scsi_dev) { 1658c20c4267SAnil Ravindranath if (fw_version <= PMCRAID_FW_VERSION_1) 1659729c8456SAnil Ravindranath res->cfg_entry.unique_flags1 &= 0x7F; 1660c20c4267SAnil Ravindranath else 166145c80be6SArnd Bergmann res->cfg_entry.array_id &= cpu_to_le16(0xFF); 166289a36810SAnil Ravindranath res->change_detected = RES_CHANGE_DEL; 166389a36810SAnil Ravindranath res->cfg_entry.resource_handle = 166489a36810SAnil Ravindranath PMCRAID_INVALID_RES_HANDLE; 166589a36810SAnil Ravindranath schedule_work(&pinstance->worker_q); 166689a36810SAnil Ravindranath } else { 166789a36810SAnil Ravindranath /* This may be one of the non-exposed resources */ 166889a36810SAnil Ravindranath list_move_tail(&res->queue, &pinstance->free_res_q); 166989a36810SAnil Ravindranath } 167089a36810SAnil Ravindranath } else if (!res->scsi_dev) { 167189a36810SAnil Ravindranath res->change_detected = RES_CHANGE_ADD; 167289a36810SAnil Ravindranath schedule_work(&pinstance->worker_q); 167389a36810SAnil Ravindranath } 167489a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); 167589a36810SAnil Ravindranath 167689a36810SAnil Ravindranath out_notify_apps: 167789a36810SAnil Ravindranath 167889a36810SAnil Ravindranath /* Notify configuration changes to registered applications.*/ 167989a36810SAnil Ravindranath if (!pmcraid_disable_aen) 1680c20c4267SAnil Ravindranath pmcraid_notify_ccn(pinstance); 168189a36810SAnil Ravindranath 168289a36810SAnil Ravindranath cmd = pmcraid_init_hcam(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE); 168389a36810SAnil Ravindranath if (cmd) 168489a36810SAnil Ravindranath pmcraid_send_hcam_cmd(cmd); 168589a36810SAnil Ravindranath } 168689a36810SAnil Ravindranath 168789a36810SAnil Ravindranath /** 168889a36810SAnil Ravindranath * pmcraid_get_error_info - return error string for an ioasc 168989a36810SAnil Ravindranath * @ioasc: ioasc code 169089a36810SAnil Ravindranath * Return Value 169189a36810SAnil Ravindranath * none 169289a36810SAnil Ravindranath */ 169389a36810SAnil Ravindranath static struct pmcraid_ioasc_error *pmcraid_get_error_info(u32 ioasc) 169489a36810SAnil Ravindranath { 169589a36810SAnil Ravindranath int i; 169689a36810SAnil Ravindranath for (i = 0; i < ARRAY_SIZE(pmcraid_ioasc_error_table); i++) { 169789a36810SAnil Ravindranath if (pmcraid_ioasc_error_table[i].ioasc_code == ioasc) 169889a36810SAnil Ravindranath return &pmcraid_ioasc_error_table[i]; 169989a36810SAnil Ravindranath } 170089a36810SAnil Ravindranath return NULL; 170189a36810SAnil Ravindranath } 170289a36810SAnil Ravindranath 170389a36810SAnil Ravindranath /** 170489a36810SAnil Ravindranath * pmcraid_ioasc_logger - log IOASC information based user-settings 170589a36810SAnil Ravindranath * @ioasc: ioasc code 170689a36810SAnil Ravindranath * @cmd: pointer to command that resulted in 'ioasc' 170789a36810SAnil Ravindranath */ 170861b96d5bSBaoyou Xie static void pmcraid_ioasc_logger(u32 ioasc, struct pmcraid_cmd *cmd) 170989a36810SAnil Ravindranath { 171089a36810SAnil Ravindranath struct pmcraid_ioasc_error *error_info = pmcraid_get_error_info(ioasc); 171189a36810SAnil Ravindranath 171289a36810SAnil Ravindranath if (error_info == NULL || 171389a36810SAnil Ravindranath cmd->drv_inst->current_log_level < error_info->log_level) 171489a36810SAnil Ravindranath return; 171589a36810SAnil Ravindranath 171689a36810SAnil Ravindranath /* log the error string */ 1717c20c4267SAnil Ravindranath pmcraid_err("cmd [%x] for resource %x failed with %x(%s)\n", 171889a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 171945c80be6SArnd Bergmann le32_to_cpu(cmd->ioa_cb->ioarcb.resource_handle), 172045c80be6SArnd Bergmann ioasc, error_info->error_string); 172189a36810SAnil Ravindranath } 172289a36810SAnil Ravindranath 172389a36810SAnil Ravindranath /** 172489a36810SAnil Ravindranath * pmcraid_handle_error_log - Handle a config change (error log) from the IOA 172589a36810SAnil Ravindranath * 172689a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 172789a36810SAnil Ravindranath * 172889a36810SAnil Ravindranath * Return value: 172989a36810SAnil Ravindranath * none 173089a36810SAnil Ravindranath */ 173189a36810SAnil Ravindranath static void pmcraid_handle_error_log(struct pmcraid_instance *pinstance) 173289a36810SAnil Ravindranath { 173389a36810SAnil Ravindranath struct pmcraid_hcam_ldn *hcam_ldn; 173489a36810SAnil Ravindranath u32 ioasc; 173589a36810SAnil Ravindranath 173689a36810SAnil Ravindranath hcam_ldn = (struct pmcraid_hcam_ldn *)pinstance->ldn.hcam; 173789a36810SAnil Ravindranath 173889a36810SAnil Ravindranath pmcraid_info 173989a36810SAnil Ravindranath ("LDN(%x): %x type: %x lost: %x flags: %x overlay id: %x\n", 174089a36810SAnil Ravindranath pinstance->ldn.hcam->ilid, 174189a36810SAnil Ravindranath pinstance->ldn.hcam->op_code, 174289a36810SAnil Ravindranath pinstance->ldn.hcam->notification_type, 174389a36810SAnil Ravindranath pinstance->ldn.hcam->notification_lost, 174489a36810SAnil Ravindranath pinstance->ldn.hcam->flags, 174589a36810SAnil Ravindranath pinstance->ldn.hcam->overlay_id); 174689a36810SAnil Ravindranath 174789a36810SAnil Ravindranath /* log only the errors, no need to log informational log entries */ 174889a36810SAnil Ravindranath if (pinstance->ldn.hcam->notification_type != 174989a36810SAnil Ravindranath NOTIFICATION_TYPE_ERROR_LOG) 175089a36810SAnil Ravindranath return; 175189a36810SAnil Ravindranath 175289a36810SAnil Ravindranath if (pinstance->ldn.hcam->notification_lost == 175389a36810SAnil Ravindranath HOSTRCB_NOTIFICATIONS_LOST) 175434876402SAnil Ravindranath dev_info(&pinstance->pdev->dev, "Error notifications lost\n"); 175589a36810SAnil Ravindranath 175689a36810SAnil Ravindranath ioasc = le32_to_cpu(hcam_ldn->error_log.fd_ioasc); 175789a36810SAnil Ravindranath 175889a36810SAnil Ravindranath if (ioasc == PMCRAID_IOASC_UA_BUS_WAS_RESET || 175989a36810SAnil Ravindranath ioasc == PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER) { 176034876402SAnil Ravindranath dev_info(&pinstance->pdev->dev, 176189a36810SAnil Ravindranath "UnitAttention due to IOA Bus Reset\n"); 176289a36810SAnil Ravindranath scsi_report_bus_reset( 176389a36810SAnil Ravindranath pinstance->host, 176489a36810SAnil Ravindranath RES_BUS(hcam_ldn->error_log.fd_ra)); 176589a36810SAnil Ravindranath } 176689a36810SAnil Ravindranath 176789a36810SAnil Ravindranath return; 176889a36810SAnil Ravindranath } 176989a36810SAnil Ravindranath 177089a36810SAnil Ravindranath /** 177189a36810SAnil Ravindranath * pmcraid_process_ccn - Op done function for a CCN. 177289a36810SAnil Ravindranath * @cmd: pointer to command struct 177389a36810SAnil Ravindranath * 177489a36810SAnil Ravindranath * This function is the op done function for a configuration 177589a36810SAnil Ravindranath * change notification 177689a36810SAnil Ravindranath * 177789a36810SAnil Ravindranath * Return value: 177889a36810SAnil Ravindranath * none 177989a36810SAnil Ravindranath */ 178089a36810SAnil Ravindranath static void pmcraid_process_ccn(struct pmcraid_cmd *cmd) 178189a36810SAnil Ravindranath { 178289a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 178389a36810SAnil Ravindranath u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); 178489a36810SAnil Ravindranath unsigned long lock_flags; 178589a36810SAnil Ravindranath 178689a36810SAnil Ravindranath pinstance->ccn.cmd = NULL; 178789a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 178889a36810SAnil Ravindranath 178989a36810SAnil Ravindranath /* If driver initiated IOA reset happened while this hcam was pending 179089a36810SAnil Ravindranath * with IOA, or IOA bringdown sequence is in progress, no need to 179189a36810SAnil Ravindranath * re-register the hcam 179289a36810SAnil Ravindranath */ 179389a36810SAnil Ravindranath if (ioasc == PMCRAID_IOASC_IOA_WAS_RESET || 179489a36810SAnil Ravindranath atomic_read(&pinstance->ccn.ignore) == 1) { 179589a36810SAnil Ravindranath return; 179689a36810SAnil Ravindranath } else if (ioasc) { 179734876402SAnil Ravindranath dev_info(&pinstance->pdev->dev, 179889a36810SAnil Ravindranath "Host RCB (CCN) failed with IOASC: 0x%08X\n", ioasc); 179989a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 180089a36810SAnil Ravindranath pmcraid_send_hcam(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE); 180189a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 180289a36810SAnil Ravindranath } else { 180389a36810SAnil Ravindranath pmcraid_handle_config_change(pinstance); 180489a36810SAnil Ravindranath } 180589a36810SAnil Ravindranath } 180689a36810SAnil Ravindranath 180789a36810SAnil Ravindranath /** 180889a36810SAnil Ravindranath * pmcraid_process_ldn - op done function for an LDN 180989a36810SAnil Ravindranath * @cmd: pointer to command block 181089a36810SAnil Ravindranath * 181189a36810SAnil Ravindranath * Return value 181289a36810SAnil Ravindranath * none 181389a36810SAnil Ravindranath */ 181489a36810SAnil Ravindranath static void pmcraid_initiate_reset(struct pmcraid_instance *); 1815592488a3SAnil Ravindranath static void pmcraid_set_timestamp(struct pmcraid_cmd *cmd); 181689a36810SAnil Ravindranath 181789a36810SAnil Ravindranath static void pmcraid_process_ldn(struct pmcraid_cmd *cmd) 181889a36810SAnil Ravindranath { 181989a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 182089a36810SAnil Ravindranath struct pmcraid_hcam_ldn *ldn_hcam = 182189a36810SAnil Ravindranath (struct pmcraid_hcam_ldn *)pinstance->ldn.hcam; 182289a36810SAnil Ravindranath u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); 182389a36810SAnil Ravindranath u32 fd_ioasc = le32_to_cpu(ldn_hcam->error_log.fd_ioasc); 182489a36810SAnil Ravindranath unsigned long lock_flags; 182589a36810SAnil Ravindranath 182689a36810SAnil Ravindranath /* return the command block back to freepool */ 182789a36810SAnil Ravindranath pinstance->ldn.cmd = NULL; 182889a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 182989a36810SAnil Ravindranath 183089a36810SAnil Ravindranath /* If driver initiated IOA reset happened while this hcam was pending 183189a36810SAnil Ravindranath * with IOA, no need to re-register the hcam as reset engine will do it 183289a36810SAnil Ravindranath * once reset sequence is complete 183389a36810SAnil Ravindranath */ 183489a36810SAnil Ravindranath if (ioasc == PMCRAID_IOASC_IOA_WAS_RESET || 183589a36810SAnil Ravindranath atomic_read(&pinstance->ccn.ignore) == 1) { 183689a36810SAnil Ravindranath return; 183789a36810SAnil Ravindranath } else if (!ioasc) { 183889a36810SAnil Ravindranath pmcraid_handle_error_log(pinstance); 183989a36810SAnil Ravindranath if (fd_ioasc == PMCRAID_IOASC_NR_IOA_RESET_REQUIRED) { 184089a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, 184189a36810SAnil Ravindranath lock_flags); 184289a36810SAnil Ravindranath pmcraid_initiate_reset(pinstance); 184389a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 184489a36810SAnil Ravindranath lock_flags); 184589a36810SAnil Ravindranath return; 184689a36810SAnil Ravindranath } 1847592488a3SAnil Ravindranath if (fd_ioasc == PMCRAID_IOASC_TIME_STAMP_OUT_OF_SYNC) { 1848592488a3SAnil Ravindranath pinstance->timestamp_error = 1; 1849592488a3SAnil Ravindranath pmcraid_set_timestamp(cmd); 1850592488a3SAnil Ravindranath } 185189a36810SAnil Ravindranath } else { 185234876402SAnil Ravindranath dev_info(&pinstance->pdev->dev, 185389a36810SAnil Ravindranath "Host RCB(LDN) failed with IOASC: 0x%08X\n", ioasc); 185489a36810SAnil Ravindranath } 185589a36810SAnil Ravindranath /* send netlink message for HCAM notification if enabled */ 185689a36810SAnil Ravindranath if (!pmcraid_disable_aen) 1857c20c4267SAnil Ravindranath pmcraid_notify_ldn(pinstance); 185889a36810SAnil Ravindranath 185989a36810SAnil Ravindranath cmd = pmcraid_init_hcam(pinstance, PMCRAID_HCAM_CODE_LOG_DATA); 186089a36810SAnil Ravindranath if (cmd) 186189a36810SAnil Ravindranath pmcraid_send_hcam_cmd(cmd); 186289a36810SAnil Ravindranath } 186389a36810SAnil Ravindranath 186489a36810SAnil Ravindranath /** 186589a36810SAnil Ravindranath * pmcraid_register_hcams - register HCAMs for CCN and LDN 186689a36810SAnil Ravindranath * 186789a36810SAnil Ravindranath * @pinstance: pointer per adapter instance structure 186889a36810SAnil Ravindranath * 186989a36810SAnil Ravindranath * Return Value 187089a36810SAnil Ravindranath * none 187189a36810SAnil Ravindranath */ 187289a36810SAnil Ravindranath static void pmcraid_register_hcams(struct pmcraid_instance *pinstance) 187389a36810SAnil Ravindranath { 187489a36810SAnil Ravindranath pmcraid_send_hcam(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE); 187589a36810SAnil Ravindranath pmcraid_send_hcam(pinstance, PMCRAID_HCAM_CODE_LOG_DATA); 187689a36810SAnil Ravindranath } 187789a36810SAnil Ravindranath 187889a36810SAnil Ravindranath /** 187989a36810SAnil Ravindranath * pmcraid_unregister_hcams - cancel HCAMs registered already 188089a36810SAnil Ravindranath * @cmd: pointer to command used as part of reset sequence 188189a36810SAnil Ravindranath */ 188289a36810SAnil Ravindranath static void pmcraid_unregister_hcams(struct pmcraid_cmd *cmd) 188389a36810SAnil Ravindranath { 188489a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 188589a36810SAnil Ravindranath 188689a36810SAnil Ravindranath /* During IOA bringdown, HCAM gets fired and tasklet proceeds with 188789a36810SAnil Ravindranath * handling hcam response though it is not necessary. In order to 188889a36810SAnil Ravindranath * prevent this, set 'ignore', so that bring-down sequence doesn't 188989a36810SAnil Ravindranath * re-send any more hcams 189089a36810SAnil Ravindranath */ 189189a36810SAnil Ravindranath atomic_set(&pinstance->ccn.ignore, 1); 189289a36810SAnil Ravindranath atomic_set(&pinstance->ldn.ignore, 1); 189389a36810SAnil Ravindranath 189489a36810SAnil Ravindranath /* If adapter reset was forced as part of runtime reset sequence, 1895c20c4267SAnil Ravindranath * start the reset sequence. Reset will be triggered even in case 1896c20c4267SAnil Ravindranath * IOA unit_check. 189789a36810SAnil Ravindranath */ 1898c20c4267SAnil Ravindranath if ((pinstance->force_ioa_reset && !pinstance->ioa_bringdown) || 1899c20c4267SAnil Ravindranath pinstance->ioa_unit_check) { 190089a36810SAnil Ravindranath pinstance->force_ioa_reset = 0; 1901c20c4267SAnil Ravindranath pinstance->ioa_unit_check = 0; 190289a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; 190389a36810SAnil Ravindranath pmcraid_reset_alert(cmd); 190489a36810SAnil Ravindranath return; 190589a36810SAnil Ravindranath } 190689a36810SAnil Ravindranath 190789a36810SAnil Ravindranath /* Driver tries to cancel HCAMs by sending ABORT TASK for each HCAM 190889a36810SAnil Ravindranath * one after the other. So CCN cancellation will be triggered by 190989a36810SAnil Ravindranath * pmcraid_cancel_ldn itself. 191089a36810SAnil Ravindranath */ 191189a36810SAnil Ravindranath pmcraid_cancel_ldn(cmd); 191289a36810SAnil Ravindranath } 191389a36810SAnil Ravindranath 191489a36810SAnil Ravindranath /** 191589a36810SAnil Ravindranath * pmcraid_reset_enable_ioa - re-enable IOA after a hard reset 191689a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 191789a36810SAnil Ravindranath * Return Value 191889a36810SAnil Ravindranath * 1 if TRANSITION_TO_OPERATIONAL is active, otherwise 0 191989a36810SAnil Ravindranath */ 192089a36810SAnil Ravindranath static void pmcraid_reinit_buffers(struct pmcraid_instance *); 192189a36810SAnil Ravindranath 192289a36810SAnil Ravindranath static int pmcraid_reset_enable_ioa(struct pmcraid_instance *pinstance) 192389a36810SAnil Ravindranath { 192489a36810SAnil Ravindranath u32 intrs; 192589a36810SAnil Ravindranath 192689a36810SAnil Ravindranath pmcraid_reinit_buffers(pinstance); 192789a36810SAnil Ravindranath intrs = pmcraid_read_interrupts(pinstance); 192889a36810SAnil Ravindranath 192989a36810SAnil Ravindranath pmcraid_enable_interrupts(pinstance, PMCRAID_PCI_INTERRUPTS); 193089a36810SAnil Ravindranath 193189a36810SAnil Ravindranath if (intrs & INTRS_TRANSITION_TO_OPERATIONAL) { 1932c20c4267SAnil Ravindranath if (!pinstance->interrupt_mode) { 193389a36810SAnil Ravindranath iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, 1934c20c4267SAnil Ravindranath pinstance->int_regs. 1935c20c4267SAnil Ravindranath ioa_host_interrupt_mask_reg); 193689a36810SAnil Ravindranath iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, 193789a36810SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_clr_reg); 1938c20c4267SAnil Ravindranath } 193989a36810SAnil Ravindranath return 1; 194089a36810SAnil Ravindranath } else { 194189a36810SAnil Ravindranath return 0; 194289a36810SAnil Ravindranath } 194389a36810SAnil Ravindranath } 194489a36810SAnil Ravindranath 194589a36810SAnil Ravindranath /** 194689a36810SAnil Ravindranath * pmcraid_soft_reset - performs a soft reset and makes IOA become ready 194789a36810SAnil Ravindranath * @cmd : pointer to reset command block 194889a36810SAnil Ravindranath * 194989a36810SAnil Ravindranath * Return Value 195089a36810SAnil Ravindranath * none 195189a36810SAnil Ravindranath */ 195289a36810SAnil Ravindranath static void pmcraid_soft_reset(struct pmcraid_cmd *cmd) 195389a36810SAnil Ravindranath { 195489a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 195589a36810SAnil Ravindranath u32 int_reg; 195689a36810SAnil Ravindranath u32 doorbell; 195789a36810SAnil Ravindranath 195889a36810SAnil Ravindranath /* There will be an interrupt when Transition to Operational bit is 195989a36810SAnil Ravindranath * set so tasklet would execute next reset task. The timeout handler 196089a36810SAnil Ravindranath * would re-initiate a reset 196189a36810SAnil Ravindranath */ 196289a36810SAnil Ravindranath cmd->cmd_done = pmcraid_ioa_reset; 196389a36810SAnil Ravindranath cmd->timer.data = (unsigned long)cmd; 196489a36810SAnil Ravindranath cmd->timer.expires = jiffies + 196589a36810SAnil Ravindranath msecs_to_jiffies(PMCRAID_TRANSOP_TIMEOUT); 196689a36810SAnil Ravindranath cmd->timer.function = (void (*)(unsigned long))pmcraid_timeout_handler; 196789a36810SAnil Ravindranath 196889a36810SAnil Ravindranath if (!timer_pending(&cmd->timer)) 196989a36810SAnil Ravindranath add_timer(&cmd->timer); 197089a36810SAnil Ravindranath 197189a36810SAnil Ravindranath /* Enable destructive diagnostics on IOA if it is not yet in 197289a36810SAnil Ravindranath * operational state 197389a36810SAnil Ravindranath */ 197489a36810SAnil Ravindranath doorbell = DOORBELL_RUNTIME_RESET | 197589a36810SAnil Ravindranath DOORBELL_ENABLE_DESTRUCTIVE_DIAGS; 197689a36810SAnil Ravindranath 1977c20c4267SAnil Ravindranath /* Since we do RESET_ALERT and Start BIST we have to again write 1978c20c4267SAnil Ravindranath * MSIX Doorbell to indicate the interrupt mode 1979c20c4267SAnil Ravindranath */ 1980c20c4267SAnil Ravindranath if (pinstance->interrupt_mode) { 1981c20c4267SAnil Ravindranath iowrite32(DOORBELL_INTR_MODE_MSIX, 1982c20c4267SAnil Ravindranath pinstance->int_regs.host_ioa_interrupt_reg); 1983c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.host_ioa_interrupt_reg); 1984c20c4267SAnil Ravindranath } 1985c20c4267SAnil Ravindranath 198689a36810SAnil Ravindranath iowrite32(doorbell, pinstance->int_regs.host_ioa_interrupt_reg); 1987c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.host_ioa_interrupt_reg), 198889a36810SAnil Ravindranath int_reg = ioread32(pinstance->int_regs.ioa_host_interrupt_reg); 1989c20c4267SAnil Ravindranath 199089a36810SAnil Ravindranath pmcraid_info("Waiting for IOA to become operational %x:%x\n", 199189a36810SAnil Ravindranath ioread32(pinstance->int_regs.host_ioa_interrupt_reg), 199289a36810SAnil Ravindranath int_reg); 199389a36810SAnil Ravindranath } 199489a36810SAnil Ravindranath 199589a36810SAnil Ravindranath /** 199689a36810SAnil Ravindranath * pmcraid_get_dump - retrieves IOA dump in case of Unit Check interrupt 199789a36810SAnil Ravindranath * 199889a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 199989a36810SAnil Ravindranath * 200089a36810SAnil Ravindranath * Return Value 200189a36810SAnil Ravindranath * none 200289a36810SAnil Ravindranath */ 200389a36810SAnil Ravindranath static void pmcraid_get_dump(struct pmcraid_instance *pinstance) 200489a36810SAnil Ravindranath { 200589a36810SAnil Ravindranath pmcraid_info("%s is not yet implemented\n", __func__); 200689a36810SAnil Ravindranath } 200789a36810SAnil Ravindranath 200889a36810SAnil Ravindranath /** 200989a36810SAnil Ravindranath * pmcraid_fail_outstanding_cmds - Fails all outstanding ops. 201089a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 201189a36810SAnil Ravindranath * 201289a36810SAnil Ravindranath * This function fails all outstanding ops. If they are submitted to IOA 201389a36810SAnil Ravindranath * already, it sends cancel all messages if IOA is still accepting IOARCBs, 201489a36810SAnil Ravindranath * otherwise just completes the commands and returns the cmd blocks to free 201589a36810SAnil Ravindranath * pool. 201689a36810SAnil Ravindranath * 201789a36810SAnil Ravindranath * Return value: 201889a36810SAnil Ravindranath * none 201989a36810SAnil Ravindranath */ 202089a36810SAnil Ravindranath static void pmcraid_fail_outstanding_cmds(struct pmcraid_instance *pinstance) 202189a36810SAnil Ravindranath { 202289a36810SAnil Ravindranath struct pmcraid_cmd *cmd, *temp; 202389a36810SAnil Ravindranath unsigned long lock_flags; 202489a36810SAnil Ravindranath 202589a36810SAnil Ravindranath /* pending command list is protected by pending_pool_lock. Its 202689a36810SAnil Ravindranath * traversal must be done as within this lock 202789a36810SAnil Ravindranath */ 202889a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->pending_pool_lock, lock_flags); 202989a36810SAnil Ravindranath list_for_each_entry_safe(cmd, temp, &pinstance->pending_cmd_pool, 203089a36810SAnil Ravindranath free_list) { 203189a36810SAnil Ravindranath list_del(&cmd->free_list); 203289a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->pending_pool_lock, 203389a36810SAnil Ravindranath lock_flags); 203489a36810SAnil Ravindranath cmd->ioa_cb->ioasa.ioasc = 203589a36810SAnil Ravindranath cpu_to_le32(PMCRAID_IOASC_IOA_WAS_RESET); 203689a36810SAnil Ravindranath cmd->ioa_cb->ioasa.ilid = 203745c80be6SArnd Bergmann cpu_to_le32(PMCRAID_DRIVER_ILID); 203889a36810SAnil Ravindranath 203989a36810SAnil Ravindranath /* In case the command timer is still running */ 204089a36810SAnil Ravindranath del_timer(&cmd->timer); 204189a36810SAnil Ravindranath 204289a36810SAnil Ravindranath /* If this is an IO command, complete it by invoking scsi_done 204389a36810SAnil Ravindranath * function. If this is one of the internal commands other 204489a36810SAnil Ravindranath * than pmcraid_ioa_reset and HCAM commands invoke cmd_done to 204589a36810SAnil Ravindranath * complete it 204689a36810SAnil Ravindranath */ 204789a36810SAnil Ravindranath if (cmd->scsi_cmd) { 204889a36810SAnil Ravindranath 204989a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; 205089a36810SAnil Ravindranath __le32 resp = cmd->ioa_cb->ioarcb.response_handle; 205189a36810SAnil Ravindranath 205289a36810SAnil Ravindranath scsi_cmd->result |= DID_ERROR << 16; 205389a36810SAnil Ravindranath 205489a36810SAnil Ravindranath scsi_dma_unmap(scsi_cmd); 205589a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 205689a36810SAnil Ravindranath 205789a36810SAnil Ravindranath pmcraid_info("failing(%d) CDB[0] = %x result: %x\n", 205889a36810SAnil Ravindranath le32_to_cpu(resp) >> 2, 205989a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 206089a36810SAnil Ravindranath scsi_cmd->result); 206189a36810SAnil Ravindranath scsi_cmd->scsi_done(scsi_cmd); 206289a36810SAnil Ravindranath } else if (cmd->cmd_done == pmcraid_internal_done || 206389a36810SAnil Ravindranath cmd->cmd_done == pmcraid_erp_done) { 206489a36810SAnil Ravindranath cmd->cmd_done(cmd); 2065c20c4267SAnil Ravindranath } else if (cmd->cmd_done != pmcraid_ioa_reset && 2066c20c4267SAnil Ravindranath cmd->cmd_done != pmcraid_ioa_shutdown_done) { 206789a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 206889a36810SAnil Ravindranath } 206989a36810SAnil Ravindranath 207089a36810SAnil Ravindranath atomic_dec(&pinstance->outstanding_cmds); 207189a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->pending_pool_lock, lock_flags); 207289a36810SAnil Ravindranath } 207389a36810SAnil Ravindranath 207489a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->pending_pool_lock, lock_flags); 207589a36810SAnil Ravindranath } 207689a36810SAnil Ravindranath 207789a36810SAnil Ravindranath /** 207889a36810SAnil Ravindranath * pmcraid_ioa_reset - Implementation of IOA reset logic 207989a36810SAnil Ravindranath * 208089a36810SAnil Ravindranath * @cmd: pointer to the cmd block to be used for entire reset process 208189a36810SAnil Ravindranath * 208289a36810SAnil Ravindranath * This function executes most of the steps required for IOA reset. This gets 208389a36810SAnil Ravindranath * called by user threads (modprobe/insmod/rmmod) timer, tasklet and midlayer's 208425985edcSLucas De Marchi * 'eh_' thread. Access to variables used for controlling the reset sequence is 208589a36810SAnil Ravindranath * synchronized using host lock. Various functions called during reset process 208689a36810SAnil Ravindranath * would make use of a single command block, pointer to which is also stored in 208789a36810SAnil Ravindranath * adapter instance structure. 208889a36810SAnil Ravindranath * 208989a36810SAnil Ravindranath * Return Value 209089a36810SAnil Ravindranath * None 209189a36810SAnil Ravindranath */ 209289a36810SAnil Ravindranath static void pmcraid_ioa_reset(struct pmcraid_cmd *cmd) 209389a36810SAnil Ravindranath { 209489a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 209589a36810SAnil Ravindranath u8 reset_complete = 0; 209689a36810SAnil Ravindranath 209789a36810SAnil Ravindranath pinstance->ioa_reset_in_progress = 1; 209889a36810SAnil Ravindranath 209989a36810SAnil Ravindranath if (pinstance->reset_cmd != cmd) { 210089a36810SAnil Ravindranath pmcraid_err("reset is called with different command block\n"); 210189a36810SAnil Ravindranath pinstance->reset_cmd = cmd; 210289a36810SAnil Ravindranath } 210389a36810SAnil Ravindranath 210489a36810SAnil Ravindranath pmcraid_info("reset_engine: state = %d, command = %p\n", 210589a36810SAnil Ravindranath pinstance->ioa_state, cmd); 210689a36810SAnil Ravindranath 210789a36810SAnil Ravindranath switch (pinstance->ioa_state) { 210889a36810SAnil Ravindranath 210989a36810SAnil Ravindranath case IOA_STATE_DEAD: 211089a36810SAnil Ravindranath /* If IOA is offline, whatever may be the reset reason, just 211189a36810SAnil Ravindranath * return. callers might be waiting on the reset wait_q, wake 211289a36810SAnil Ravindranath * up them 211389a36810SAnil Ravindranath */ 211489a36810SAnil Ravindranath pmcraid_err("IOA is offline no reset is possible\n"); 211589a36810SAnil Ravindranath reset_complete = 1; 211689a36810SAnil Ravindranath break; 211789a36810SAnil Ravindranath 211889a36810SAnil Ravindranath case IOA_STATE_IN_BRINGDOWN: 211989a36810SAnil Ravindranath /* we enter here, once ioa shutdown command is processed by IOA 212089a36810SAnil Ravindranath * Alert IOA for a possible reset. If reset alert fails, IOA 212189a36810SAnil Ravindranath * goes through hard-reset 212289a36810SAnil Ravindranath */ 212389a36810SAnil Ravindranath pmcraid_disable_interrupts(pinstance, ~0); 212489a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; 212589a36810SAnil Ravindranath pmcraid_reset_alert(cmd); 212689a36810SAnil Ravindranath break; 212789a36810SAnil Ravindranath 212889a36810SAnil Ravindranath case IOA_STATE_UNKNOWN: 212989a36810SAnil Ravindranath /* We may be called during probe or resume. Some pre-processing 213089a36810SAnil Ravindranath * is required for prior to reset 213189a36810SAnil Ravindranath */ 213289a36810SAnil Ravindranath scsi_block_requests(pinstance->host); 213389a36810SAnil Ravindranath 213489a36810SAnil Ravindranath /* If asked to reset while IOA was processing responses or 213589a36810SAnil Ravindranath * there are any error responses then IOA may require 213689a36810SAnil Ravindranath * hard-reset. 213789a36810SAnil Ravindranath */ 213889a36810SAnil Ravindranath if (pinstance->ioa_hard_reset == 0) { 213989a36810SAnil Ravindranath if (ioread32(pinstance->ioa_status) & 214089a36810SAnil Ravindranath INTRS_TRANSITION_TO_OPERATIONAL) { 214189a36810SAnil Ravindranath pmcraid_info("sticky bit set, bring-up\n"); 214289a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_BRINGUP; 214389a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 214489a36810SAnil Ravindranath pmcraid_identify_hrrq(cmd); 214589a36810SAnil Ravindranath } else { 214689a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_SOFT_RESET; 214789a36810SAnil Ravindranath pmcraid_soft_reset(cmd); 214889a36810SAnil Ravindranath } 214989a36810SAnil Ravindranath } else { 215089a36810SAnil Ravindranath /* Alert IOA of a possible reset and wait for critical 215189a36810SAnil Ravindranath * operation in progress bit to reset 215289a36810SAnil Ravindranath */ 215389a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; 215489a36810SAnil Ravindranath pmcraid_reset_alert(cmd); 215589a36810SAnil Ravindranath } 215689a36810SAnil Ravindranath break; 215789a36810SAnil Ravindranath 215889a36810SAnil Ravindranath case IOA_STATE_IN_RESET_ALERT: 215989a36810SAnil Ravindranath /* If critical operation in progress bit is reset or wait gets 216089a36810SAnil Ravindranath * timed out, reset proceeds with starting BIST on the IOA. 216189a36810SAnil Ravindranath * pmcraid_ioa_hard_reset keeps a count of reset attempts. If 216289a36810SAnil Ravindranath * they are 3 or more, reset engine marks IOA dead and returns 216389a36810SAnil Ravindranath */ 216489a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_HARD_RESET; 216589a36810SAnil Ravindranath pmcraid_start_bist(cmd); 216689a36810SAnil Ravindranath break; 216789a36810SAnil Ravindranath 216889a36810SAnil Ravindranath case IOA_STATE_IN_HARD_RESET: 216989a36810SAnil Ravindranath pinstance->ioa_reset_attempts++; 217089a36810SAnil Ravindranath 217189a36810SAnil Ravindranath /* retry reset if we haven't reached maximum allowed limit */ 217289a36810SAnil Ravindranath if (pinstance->ioa_reset_attempts > PMCRAID_RESET_ATTEMPTS) { 217389a36810SAnil Ravindranath pinstance->ioa_reset_attempts = 0; 217489a36810SAnil Ravindranath pmcraid_err("IOA didn't respond marking it as dead\n"); 217589a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_DEAD; 2176c20c4267SAnil Ravindranath 2177c20c4267SAnil Ravindranath if (pinstance->ioa_bringdown) 2178c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, 2179c20c4267SAnil Ravindranath PMC_DEVICE_EVENT_SHUTDOWN_FAILED); 2180c20c4267SAnil Ravindranath else 2181c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, 2182c20c4267SAnil Ravindranath PMC_DEVICE_EVENT_RESET_FAILED); 218389a36810SAnil Ravindranath reset_complete = 1; 218489a36810SAnil Ravindranath break; 218589a36810SAnil Ravindranath } 218689a36810SAnil Ravindranath 218789a36810SAnil Ravindranath /* Once either bist or pci reset is done, restore PCI config 218889a36810SAnil Ravindranath * space. If this fails, proceed with hard reset again 218989a36810SAnil Ravindranath */ 21901d3c16a8SJon Mason pci_restore_state(pinstance->pdev); 219189a36810SAnil Ravindranath 219289a36810SAnil Ravindranath /* fail all pending commands */ 219389a36810SAnil Ravindranath pmcraid_fail_outstanding_cmds(pinstance); 219489a36810SAnil Ravindranath 219589a36810SAnil Ravindranath /* check if unit check is active, if so extract dump */ 219689a36810SAnil Ravindranath if (pinstance->ioa_unit_check) { 219789a36810SAnil Ravindranath pmcraid_info("unit check is active\n"); 219889a36810SAnil Ravindranath pinstance->ioa_unit_check = 0; 219989a36810SAnil Ravindranath pmcraid_get_dump(pinstance); 220089a36810SAnil Ravindranath pinstance->ioa_reset_attempts--; 220189a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; 220289a36810SAnil Ravindranath pmcraid_reset_alert(cmd); 220389a36810SAnil Ravindranath break; 220489a36810SAnil Ravindranath } 220589a36810SAnil Ravindranath 220689a36810SAnil Ravindranath /* if the reset reason is to bring-down the ioa, we might be 220789a36810SAnil Ravindranath * done with the reset restore pci_config_space and complete 220889a36810SAnil Ravindranath * the reset 220989a36810SAnil Ravindranath */ 221089a36810SAnil Ravindranath if (pinstance->ioa_bringdown) { 221189a36810SAnil Ravindranath pmcraid_info("bringing down the adapter\n"); 221289a36810SAnil Ravindranath pinstance->ioa_shutdown_type = SHUTDOWN_NONE; 221389a36810SAnil Ravindranath pinstance->ioa_bringdown = 0; 221489a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_UNKNOWN; 2215c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, 2216c20c4267SAnil Ravindranath PMC_DEVICE_EVENT_SHUTDOWN_SUCCESS); 221789a36810SAnil Ravindranath reset_complete = 1; 221889a36810SAnil Ravindranath } else { 221989a36810SAnil Ravindranath /* bring-up IOA, so proceed with soft reset 222089a36810SAnil Ravindranath * Reinitialize hrrq_buffers and their indices also 222189a36810SAnil Ravindranath * enable interrupts after a pci_restore_state 222289a36810SAnil Ravindranath */ 222389a36810SAnil Ravindranath if (pmcraid_reset_enable_ioa(pinstance)) { 222489a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_BRINGUP; 222589a36810SAnil Ravindranath pmcraid_info("bringing up the adapter\n"); 222689a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 222789a36810SAnil Ravindranath pmcraid_identify_hrrq(cmd); 222889a36810SAnil Ravindranath } else { 222989a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_SOFT_RESET; 223089a36810SAnil Ravindranath pmcraid_soft_reset(cmd); 223189a36810SAnil Ravindranath } 223289a36810SAnil Ravindranath } 223389a36810SAnil Ravindranath break; 223489a36810SAnil Ravindranath 223589a36810SAnil Ravindranath case IOA_STATE_IN_SOFT_RESET: 223689a36810SAnil Ravindranath /* TRANSITION TO OPERATIONAL is on so start initialization 223789a36810SAnil Ravindranath * sequence 223889a36810SAnil Ravindranath */ 223989a36810SAnil Ravindranath pmcraid_info("In softreset proceeding with bring-up\n"); 224089a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_BRINGUP; 224189a36810SAnil Ravindranath 224289a36810SAnil Ravindranath /* Initialization commands start with HRRQ identification. From 224389a36810SAnil Ravindranath * now on tasklet completes most of the commands as IOA is up 224489a36810SAnil Ravindranath * and intrs are enabled 224589a36810SAnil Ravindranath */ 224689a36810SAnil Ravindranath pmcraid_identify_hrrq(cmd); 224789a36810SAnil Ravindranath break; 224889a36810SAnil Ravindranath 224989a36810SAnil Ravindranath case IOA_STATE_IN_BRINGUP: 225089a36810SAnil Ravindranath /* we are done with bringing up of IOA, change the ioa_state to 225189a36810SAnil Ravindranath * operational and wake up any waiters 225289a36810SAnil Ravindranath */ 225389a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_OPERATIONAL; 225489a36810SAnil Ravindranath reset_complete = 1; 225589a36810SAnil Ravindranath break; 225689a36810SAnil Ravindranath 225789a36810SAnil Ravindranath case IOA_STATE_OPERATIONAL: 225889a36810SAnil Ravindranath default: 225989a36810SAnil Ravindranath /* When IOA is operational and a reset is requested, check for 226089a36810SAnil Ravindranath * the reset reason. If reset is to bring down IOA, unregister 226189a36810SAnil Ravindranath * HCAMs and initiate shutdown; if adapter reset is forced then 226289a36810SAnil Ravindranath * restart reset sequence again 226389a36810SAnil Ravindranath */ 226489a36810SAnil Ravindranath if (pinstance->ioa_shutdown_type == SHUTDOWN_NONE && 226589a36810SAnil Ravindranath pinstance->force_ioa_reset == 0) { 2266c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, 2267c20c4267SAnil Ravindranath PMC_DEVICE_EVENT_RESET_SUCCESS); 226889a36810SAnil Ravindranath reset_complete = 1; 226989a36810SAnil Ravindranath } else { 227089a36810SAnil Ravindranath if (pinstance->ioa_shutdown_type != SHUTDOWN_NONE) 227189a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_BRINGDOWN; 227289a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 227389a36810SAnil Ravindranath pmcraid_unregister_hcams(cmd); 227489a36810SAnil Ravindranath } 227589a36810SAnil Ravindranath break; 227689a36810SAnil Ravindranath } 227789a36810SAnil Ravindranath 227889a36810SAnil Ravindranath /* reset will be completed if ioa_state is either DEAD or UNKNOWN or 227989a36810SAnil Ravindranath * OPERATIONAL. Reset all control variables used during reset, wake up 228089a36810SAnil Ravindranath * any waiting threads and let the SCSI mid-layer send commands. Note 228189a36810SAnil Ravindranath * that host_lock must be held before invoking scsi_report_bus_reset. 228289a36810SAnil Ravindranath */ 228389a36810SAnil Ravindranath if (reset_complete) { 228489a36810SAnil Ravindranath pinstance->ioa_reset_in_progress = 0; 228589a36810SAnil Ravindranath pinstance->ioa_reset_attempts = 0; 228689a36810SAnil Ravindranath pinstance->reset_cmd = NULL; 228789a36810SAnil Ravindranath pinstance->ioa_shutdown_type = SHUTDOWN_NONE; 228889a36810SAnil Ravindranath pinstance->ioa_bringdown = 0; 228989a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 229089a36810SAnil Ravindranath 229189a36810SAnil Ravindranath /* If target state is to bring up the adapter, proceed with 229289a36810SAnil Ravindranath * hcam registration and resource exposure to mid-layer. 229389a36810SAnil Ravindranath */ 229489a36810SAnil Ravindranath if (pinstance->ioa_state == IOA_STATE_OPERATIONAL) 229589a36810SAnil Ravindranath pmcraid_register_hcams(pinstance); 229689a36810SAnil Ravindranath 229789a36810SAnil Ravindranath wake_up_all(&pinstance->reset_wait_q); 229889a36810SAnil Ravindranath } 229989a36810SAnil Ravindranath 230089a36810SAnil Ravindranath return; 230189a36810SAnil Ravindranath } 230289a36810SAnil Ravindranath 230389a36810SAnil Ravindranath /** 230489a36810SAnil Ravindranath * pmcraid_initiate_reset - initiates reset sequence. This is called from 230589a36810SAnil Ravindranath * ISR/tasklet during error interrupts including IOA unit check. If reset 230689a36810SAnil Ravindranath * is already in progress, it just returns, otherwise initiates IOA reset 230789a36810SAnil Ravindranath * to bring IOA up to operational state. 230889a36810SAnil Ravindranath * 230989a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 231089a36810SAnil Ravindranath * 231189a36810SAnil Ravindranath * Return value 231289a36810SAnil Ravindranath * none 231389a36810SAnil Ravindranath */ 231489a36810SAnil Ravindranath static void pmcraid_initiate_reset(struct pmcraid_instance *pinstance) 231589a36810SAnil Ravindranath { 231689a36810SAnil Ravindranath struct pmcraid_cmd *cmd; 231789a36810SAnil Ravindranath 231889a36810SAnil Ravindranath /* If the reset is already in progress, just return, otherwise start 231989a36810SAnil Ravindranath * reset sequence and return 232089a36810SAnil Ravindranath */ 232189a36810SAnil Ravindranath if (!pinstance->ioa_reset_in_progress) { 232289a36810SAnil Ravindranath scsi_block_requests(pinstance->host); 232389a36810SAnil Ravindranath cmd = pmcraid_get_free_cmd(pinstance); 232489a36810SAnil Ravindranath 232589a36810SAnil Ravindranath if (cmd == NULL) { 232689a36810SAnil Ravindranath pmcraid_err("no cmnd blocks for initiate_reset\n"); 232789a36810SAnil Ravindranath return; 232889a36810SAnil Ravindranath } 232989a36810SAnil Ravindranath 233089a36810SAnil Ravindranath pinstance->ioa_shutdown_type = SHUTDOWN_NONE; 233189a36810SAnil Ravindranath pinstance->reset_cmd = cmd; 233289a36810SAnil Ravindranath pinstance->force_ioa_reset = 1; 2333c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, 2334c20c4267SAnil Ravindranath PMC_DEVICE_EVENT_RESET_START); 233589a36810SAnil Ravindranath pmcraid_ioa_reset(cmd); 233689a36810SAnil Ravindranath } 233789a36810SAnil Ravindranath } 233889a36810SAnil Ravindranath 233989a36810SAnil Ravindranath /** 234089a36810SAnil Ravindranath * pmcraid_reset_reload - utility routine for doing IOA reset either to bringup 234189a36810SAnil Ravindranath * or bringdown IOA 234289a36810SAnil Ravindranath * @pinstance: pointer adapter instance structure 234389a36810SAnil Ravindranath * @shutdown_type: shutdown type to be used NONE, NORMAL or ABRREV 234489a36810SAnil Ravindranath * @target_state: expected target state after reset 234589a36810SAnil Ravindranath * 234689a36810SAnil Ravindranath * Note: This command initiates reset and waits for its completion. Hence this 234789a36810SAnil Ravindranath * should not be called from isr/timer/tasklet functions (timeout handlers, 234889a36810SAnil Ravindranath * error response handlers and interrupt handlers). 234989a36810SAnil Ravindranath * 235089a36810SAnil Ravindranath * Return Value 235189a36810SAnil Ravindranath * 1 in case ioa_state is not target_state, 0 otherwise. 235289a36810SAnil Ravindranath */ 235389a36810SAnil Ravindranath static int pmcraid_reset_reload( 235489a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 235589a36810SAnil Ravindranath u8 shutdown_type, 235689a36810SAnil Ravindranath u8 target_state 235789a36810SAnil Ravindranath ) 235889a36810SAnil Ravindranath { 235989a36810SAnil Ravindranath struct pmcraid_cmd *reset_cmd = NULL; 236089a36810SAnil Ravindranath unsigned long lock_flags; 236189a36810SAnil Ravindranath int reset = 1; 236289a36810SAnil Ravindranath 236389a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 236489a36810SAnil Ravindranath 236589a36810SAnil Ravindranath if (pinstance->ioa_reset_in_progress) { 236689a36810SAnil Ravindranath pmcraid_info("reset_reload: reset is already in progress\n"); 236789a36810SAnil Ravindranath 236889a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 236989a36810SAnil Ravindranath 237089a36810SAnil Ravindranath wait_event(pinstance->reset_wait_q, 237189a36810SAnil Ravindranath !pinstance->ioa_reset_in_progress); 237289a36810SAnil Ravindranath 237389a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 237489a36810SAnil Ravindranath 237589a36810SAnil Ravindranath if (pinstance->ioa_state == IOA_STATE_DEAD) { 237689a36810SAnil Ravindranath pmcraid_info("reset_reload: IOA is dead\n"); 237791402608SChristoph Hellwig goto out_unlock; 237891402608SChristoph Hellwig } 237991402608SChristoph Hellwig 238091402608SChristoph Hellwig if (pinstance->ioa_state == target_state) { 238189a36810SAnil Ravindranath reset = 0; 238291402608SChristoph Hellwig goto out_unlock; 238389a36810SAnil Ravindranath } 238489a36810SAnil Ravindranath } 238589a36810SAnil Ravindranath 238689a36810SAnil Ravindranath pmcraid_info("reset_reload: proceeding with reset\n"); 238789a36810SAnil Ravindranath scsi_block_requests(pinstance->host); 238889a36810SAnil Ravindranath reset_cmd = pmcraid_get_free_cmd(pinstance); 238989a36810SAnil Ravindranath if (reset_cmd == NULL) { 239089a36810SAnil Ravindranath pmcraid_err("no free cmnd for reset_reload\n"); 239191402608SChristoph Hellwig goto out_unlock; 239289a36810SAnil Ravindranath } 239389a36810SAnil Ravindranath 239489a36810SAnil Ravindranath if (shutdown_type == SHUTDOWN_NORMAL) 239589a36810SAnil Ravindranath pinstance->ioa_bringdown = 1; 239689a36810SAnil Ravindranath 239789a36810SAnil Ravindranath pinstance->ioa_shutdown_type = shutdown_type; 239889a36810SAnil Ravindranath pinstance->reset_cmd = reset_cmd; 239989a36810SAnil Ravindranath pinstance->force_ioa_reset = reset; 240089a36810SAnil Ravindranath pmcraid_info("reset_reload: initiating reset\n"); 240189a36810SAnil Ravindranath pmcraid_ioa_reset(reset_cmd); 240289a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 240389a36810SAnil Ravindranath pmcraid_info("reset_reload: waiting for reset to complete\n"); 240489a36810SAnil Ravindranath wait_event(pinstance->reset_wait_q, 240589a36810SAnil Ravindranath !pinstance->ioa_reset_in_progress); 240689a36810SAnil Ravindranath 240789a36810SAnil Ravindranath pmcraid_info("reset_reload: reset is complete !!\n"); 240889a36810SAnil Ravindranath scsi_unblock_requests(pinstance->host); 240991402608SChristoph Hellwig return pinstance->ioa_state != target_state; 241089a36810SAnil Ravindranath 241191402608SChristoph Hellwig out_unlock: 241291402608SChristoph Hellwig spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 241389a36810SAnil Ravindranath return reset; 241489a36810SAnil Ravindranath } 241589a36810SAnil Ravindranath 241689a36810SAnil Ravindranath /** 241789a36810SAnil Ravindranath * pmcraid_reset_bringdown - wrapper over pmcraid_reset_reload to bringdown IOA 241889a36810SAnil Ravindranath * 241989a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 242089a36810SAnil Ravindranath * 242189a36810SAnil Ravindranath * Return Value 242289a36810SAnil Ravindranath * whatever is returned from pmcraid_reset_reload 242389a36810SAnil Ravindranath */ 242489a36810SAnil Ravindranath static int pmcraid_reset_bringdown(struct pmcraid_instance *pinstance) 242589a36810SAnil Ravindranath { 242689a36810SAnil Ravindranath return pmcraid_reset_reload(pinstance, 242789a36810SAnil Ravindranath SHUTDOWN_NORMAL, 242889a36810SAnil Ravindranath IOA_STATE_UNKNOWN); 242989a36810SAnil Ravindranath } 243089a36810SAnil Ravindranath 243189a36810SAnil Ravindranath /** 243289a36810SAnil Ravindranath * pmcraid_reset_bringup - wrapper over pmcraid_reset_reload to bring up IOA 243389a36810SAnil Ravindranath * 243489a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 243589a36810SAnil Ravindranath * 243689a36810SAnil Ravindranath * Return Value 243789a36810SAnil Ravindranath * whatever is returned from pmcraid_reset_reload 243889a36810SAnil Ravindranath */ 243989a36810SAnil Ravindranath static int pmcraid_reset_bringup(struct pmcraid_instance *pinstance) 244089a36810SAnil Ravindranath { 2441c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, PMC_DEVICE_EVENT_RESET_START); 2442c20c4267SAnil Ravindranath 244389a36810SAnil Ravindranath return pmcraid_reset_reload(pinstance, 244489a36810SAnil Ravindranath SHUTDOWN_NONE, 244589a36810SAnil Ravindranath IOA_STATE_OPERATIONAL); 244689a36810SAnil Ravindranath } 244789a36810SAnil Ravindranath 244889a36810SAnil Ravindranath /** 244989a36810SAnil Ravindranath * pmcraid_request_sense - Send request sense to a device 245089a36810SAnil Ravindranath * @cmd: pmcraid command struct 245189a36810SAnil Ravindranath * 245289a36810SAnil Ravindranath * This function sends a request sense to a device as a result of a check 245389a36810SAnil Ravindranath * condition. This method re-uses the same command block that failed earlier. 245489a36810SAnil Ravindranath */ 245589a36810SAnil Ravindranath static void pmcraid_request_sense(struct pmcraid_cmd *cmd) 245689a36810SAnil Ravindranath { 245789a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 245889a36810SAnil Ravindranath struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; 245989a36810SAnil Ravindranath 246089a36810SAnil Ravindranath /* allocate DMAable memory for sense buffers */ 246189a36810SAnil Ravindranath cmd->sense_buffer = pci_alloc_consistent(cmd->drv_inst->pdev, 246289a36810SAnil Ravindranath SCSI_SENSE_BUFFERSIZE, 246389a36810SAnil Ravindranath &cmd->sense_buffer_dma); 246489a36810SAnil Ravindranath 246589a36810SAnil Ravindranath if (cmd->sense_buffer == NULL) { 246689a36810SAnil Ravindranath pmcraid_err 246789a36810SAnil Ravindranath ("couldn't allocate sense buffer for request sense\n"); 246889a36810SAnil Ravindranath pmcraid_erp_done(cmd); 246989a36810SAnil Ravindranath return; 247089a36810SAnil Ravindranath } 247189a36810SAnil Ravindranath 247289a36810SAnil Ravindranath /* re-use the command block */ 247389a36810SAnil Ravindranath memset(&cmd->ioa_cb->ioasa, 0, sizeof(struct pmcraid_ioasa)); 247489a36810SAnil Ravindranath memset(ioarcb->cdb, 0, PMCRAID_MAX_CDB_LEN); 247589a36810SAnil Ravindranath ioarcb->request_flags0 = (SYNC_COMPLETE | 247689a36810SAnil Ravindranath NO_LINK_DESCS | 247789a36810SAnil Ravindranath INHIBIT_UL_CHECK); 247889a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_SCSI; 247989a36810SAnil Ravindranath ioarcb->cdb[0] = REQUEST_SENSE; 248089a36810SAnil Ravindranath ioarcb->cdb[4] = SCSI_SENSE_BUFFERSIZE; 248189a36810SAnil Ravindranath 248289a36810SAnil Ravindranath ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + 248389a36810SAnil Ravindranath offsetof(struct pmcraid_ioarcb, 248489a36810SAnil Ravindranath add_data.u.ioadl[0])); 248589a36810SAnil Ravindranath ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); 248689a36810SAnil Ravindranath 248789a36810SAnil Ravindranath ioarcb->data_transfer_length = cpu_to_le32(SCSI_SENSE_BUFFERSIZE); 248889a36810SAnil Ravindranath 248989a36810SAnil Ravindranath ioadl->address = cpu_to_le64(cmd->sense_buffer_dma); 249089a36810SAnil Ravindranath ioadl->data_len = cpu_to_le32(SCSI_SENSE_BUFFERSIZE); 249188197966SAnil Ravindranath ioadl->flags = IOADL_FLAGS_LAST_DESC; 249289a36810SAnil Ravindranath 249389a36810SAnil Ravindranath /* request sense might be called as part of error response processing 249489a36810SAnil Ravindranath * which runs in tasklets context. It is possible that mid-layer might 249589a36810SAnil Ravindranath * schedule queuecommand during this time, hence, writting to IOARRIN 249689a36810SAnil Ravindranath * must be protect by host_lock 249789a36810SAnil Ravindranath */ 249889a36810SAnil Ravindranath pmcraid_send_cmd(cmd, pmcraid_erp_done, 249989a36810SAnil Ravindranath PMCRAID_REQUEST_SENSE_TIMEOUT, 250089a36810SAnil Ravindranath pmcraid_timeout_handler); 250189a36810SAnil Ravindranath } 250289a36810SAnil Ravindranath 250389a36810SAnil Ravindranath /** 250489a36810SAnil Ravindranath * pmcraid_cancel_all - cancel all outstanding IOARCBs as part of error recovery 250589a36810SAnil Ravindranath * @cmd: command that failed 250689a36810SAnil Ravindranath * @sense: true if request_sense is required after cancel all 250789a36810SAnil Ravindranath * 250889a36810SAnil Ravindranath * This function sends a cancel all to a device to clear the queue. 250989a36810SAnil Ravindranath */ 251089a36810SAnil Ravindranath static void pmcraid_cancel_all(struct pmcraid_cmd *cmd, u32 sense) 251189a36810SAnil Ravindranath { 251289a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; 251389a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 251489a36810SAnil Ravindranath struct pmcraid_resource_entry *res = scsi_cmd->device->hostdata; 251589a36810SAnil Ravindranath void (*cmd_done) (struct pmcraid_cmd *) = sense ? pmcraid_erp_done 251689a36810SAnil Ravindranath : pmcraid_request_sense; 251789a36810SAnil Ravindranath 251889a36810SAnil Ravindranath memset(ioarcb->cdb, 0, PMCRAID_MAX_CDB_LEN); 251989a36810SAnil Ravindranath ioarcb->request_flags0 = SYNC_OVERRIDE; 252089a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_IOACMD; 252189a36810SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_CANCEL_ALL_REQUESTS; 252289a36810SAnil Ravindranath 252389a36810SAnil Ravindranath if (RES_IS_GSCSI(res->cfg_entry)) 252489a36810SAnil Ravindranath ioarcb->cdb[1] = PMCRAID_SYNC_COMPLETE_AFTER_CANCEL; 252589a36810SAnil Ravindranath 252689a36810SAnil Ravindranath ioarcb->ioadl_bus_addr = 0; 252789a36810SAnil Ravindranath ioarcb->ioadl_length = 0; 252889a36810SAnil Ravindranath ioarcb->data_transfer_length = 0; 252945c80be6SArnd Bergmann ioarcb->ioarcb_bus_addr &= cpu_to_le64((~0x1FULL)); 253089a36810SAnil Ravindranath 253189a36810SAnil Ravindranath /* writing to IOARRIN must be protected by host_lock, as mid-layer 253289a36810SAnil Ravindranath * schedule queuecommand while we are doing this 253389a36810SAnil Ravindranath */ 253489a36810SAnil Ravindranath pmcraid_send_cmd(cmd, cmd_done, 253589a36810SAnil Ravindranath PMCRAID_REQUEST_SENSE_TIMEOUT, 253689a36810SAnil Ravindranath pmcraid_timeout_handler); 253789a36810SAnil Ravindranath } 253889a36810SAnil Ravindranath 253989a36810SAnil Ravindranath /** 254089a36810SAnil Ravindranath * pmcraid_frame_auto_sense: frame fixed format sense information 254189a36810SAnil Ravindranath * 254289a36810SAnil Ravindranath * @cmd: pointer to failing command block 254389a36810SAnil Ravindranath * 254489a36810SAnil Ravindranath * Return value 254589a36810SAnil Ravindranath * none 254689a36810SAnil Ravindranath */ 254789a36810SAnil Ravindranath static void pmcraid_frame_auto_sense(struct pmcraid_cmd *cmd) 254889a36810SAnil Ravindranath { 254989a36810SAnil Ravindranath u8 *sense_buf = cmd->scsi_cmd->sense_buffer; 255089a36810SAnil Ravindranath struct pmcraid_resource_entry *res = cmd->scsi_cmd->device->hostdata; 255189a36810SAnil Ravindranath struct pmcraid_ioasa *ioasa = &cmd->ioa_cb->ioasa; 255289a36810SAnil Ravindranath u32 ioasc = le32_to_cpu(ioasa->ioasc); 255389a36810SAnil Ravindranath u32 failing_lba = 0; 255489a36810SAnil Ravindranath 255589a36810SAnil Ravindranath memset(sense_buf, 0, SCSI_SENSE_BUFFERSIZE); 255689a36810SAnil Ravindranath cmd->scsi_cmd->result = SAM_STAT_CHECK_CONDITION; 255789a36810SAnil Ravindranath 255889a36810SAnil Ravindranath if (RES_IS_VSET(res->cfg_entry) && 255989a36810SAnil Ravindranath ioasc == PMCRAID_IOASC_ME_READ_ERROR_NO_REALLOC && 256089a36810SAnil Ravindranath ioasa->u.vset.failing_lba_hi != 0) { 256189a36810SAnil Ravindranath 256289a36810SAnil Ravindranath sense_buf[0] = 0x72; 256389a36810SAnil Ravindranath sense_buf[1] = PMCRAID_IOASC_SENSE_KEY(ioasc); 256489a36810SAnil Ravindranath sense_buf[2] = PMCRAID_IOASC_SENSE_CODE(ioasc); 256589a36810SAnil Ravindranath sense_buf[3] = PMCRAID_IOASC_SENSE_QUAL(ioasc); 256689a36810SAnil Ravindranath 256789a36810SAnil Ravindranath sense_buf[7] = 12; 256889a36810SAnil Ravindranath sense_buf[8] = 0; 256989a36810SAnil Ravindranath sense_buf[9] = 0x0A; 257089a36810SAnil Ravindranath sense_buf[10] = 0x80; 257189a36810SAnil Ravindranath 257289a36810SAnil Ravindranath failing_lba = le32_to_cpu(ioasa->u.vset.failing_lba_hi); 257389a36810SAnil Ravindranath 257489a36810SAnil Ravindranath sense_buf[12] = (failing_lba & 0xff000000) >> 24; 257589a36810SAnil Ravindranath sense_buf[13] = (failing_lba & 0x00ff0000) >> 16; 257689a36810SAnil Ravindranath sense_buf[14] = (failing_lba & 0x0000ff00) >> 8; 257789a36810SAnil Ravindranath sense_buf[15] = failing_lba & 0x000000ff; 257889a36810SAnil Ravindranath 257989a36810SAnil Ravindranath failing_lba = le32_to_cpu(ioasa->u.vset.failing_lba_lo); 258089a36810SAnil Ravindranath 258189a36810SAnil Ravindranath sense_buf[16] = (failing_lba & 0xff000000) >> 24; 258289a36810SAnil Ravindranath sense_buf[17] = (failing_lba & 0x00ff0000) >> 16; 258389a36810SAnil Ravindranath sense_buf[18] = (failing_lba & 0x0000ff00) >> 8; 258489a36810SAnil Ravindranath sense_buf[19] = failing_lba & 0x000000ff; 258589a36810SAnil Ravindranath } else { 258689a36810SAnil Ravindranath sense_buf[0] = 0x70; 258789a36810SAnil Ravindranath sense_buf[2] = PMCRAID_IOASC_SENSE_KEY(ioasc); 258889a36810SAnil Ravindranath sense_buf[12] = PMCRAID_IOASC_SENSE_CODE(ioasc); 258989a36810SAnil Ravindranath sense_buf[13] = PMCRAID_IOASC_SENSE_QUAL(ioasc); 259089a36810SAnil Ravindranath 259189a36810SAnil Ravindranath if (ioasc == PMCRAID_IOASC_ME_READ_ERROR_NO_REALLOC) { 259289a36810SAnil Ravindranath if (RES_IS_VSET(res->cfg_entry)) 259389a36810SAnil Ravindranath failing_lba = 259489a36810SAnil Ravindranath le32_to_cpu(ioasa->u. 259589a36810SAnil Ravindranath vset.failing_lba_lo); 259689a36810SAnil Ravindranath sense_buf[0] |= 0x80; 259789a36810SAnil Ravindranath sense_buf[3] = (failing_lba >> 24) & 0xff; 259889a36810SAnil Ravindranath sense_buf[4] = (failing_lba >> 16) & 0xff; 259989a36810SAnil Ravindranath sense_buf[5] = (failing_lba >> 8) & 0xff; 260089a36810SAnil Ravindranath sense_buf[6] = failing_lba & 0xff; 260189a36810SAnil Ravindranath } 260289a36810SAnil Ravindranath 260389a36810SAnil Ravindranath sense_buf[7] = 6; /* additional length */ 260489a36810SAnil Ravindranath } 260589a36810SAnil Ravindranath } 260689a36810SAnil Ravindranath 260789a36810SAnil Ravindranath /** 260889a36810SAnil Ravindranath * pmcraid_error_handler - Error response handlers for a SCSI op 260989a36810SAnil Ravindranath * @cmd: pointer to pmcraid_cmd that has failed 261089a36810SAnil Ravindranath * 261189a36810SAnil Ravindranath * This function determines whether or not to initiate ERP on the affected 261289a36810SAnil Ravindranath * device. This is called from a tasklet, which doesn't hold any locks. 261389a36810SAnil Ravindranath * 261489a36810SAnil Ravindranath * Return value: 261589a36810SAnil Ravindranath * 0 it caller can complete the request, otherwise 1 where in error 261689a36810SAnil Ravindranath * handler itself completes the request and returns the command block 261789a36810SAnil Ravindranath * back to free-pool 261889a36810SAnil Ravindranath */ 261989a36810SAnil Ravindranath static int pmcraid_error_handler(struct pmcraid_cmd *cmd) 262089a36810SAnil Ravindranath { 262189a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; 262289a36810SAnil Ravindranath struct pmcraid_resource_entry *res = scsi_cmd->device->hostdata; 262389a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 262489a36810SAnil Ravindranath struct pmcraid_ioasa *ioasa = &cmd->ioa_cb->ioasa; 262589a36810SAnil Ravindranath u32 ioasc = le32_to_cpu(ioasa->ioasc); 262689a36810SAnil Ravindranath u32 masked_ioasc = ioasc & PMCRAID_IOASC_SENSE_MASK; 262789a36810SAnil Ravindranath u32 sense_copied = 0; 262889a36810SAnil Ravindranath 262989a36810SAnil Ravindranath if (!res) { 263089a36810SAnil Ravindranath pmcraid_info("resource pointer is NULL\n"); 263189a36810SAnil Ravindranath return 0; 263289a36810SAnil Ravindranath } 263389a36810SAnil Ravindranath 263489a36810SAnil Ravindranath /* If this was a SCSI read/write command keep count of errors */ 263589a36810SAnil Ravindranath if (SCSI_CMD_TYPE(scsi_cmd->cmnd[0]) == SCSI_READ_CMD) 263689a36810SAnil Ravindranath atomic_inc(&res->read_failures); 263789a36810SAnil Ravindranath else if (SCSI_CMD_TYPE(scsi_cmd->cmnd[0]) == SCSI_WRITE_CMD) 263889a36810SAnil Ravindranath atomic_inc(&res->write_failures); 263989a36810SAnil Ravindranath 264089a36810SAnil Ravindranath if (!RES_IS_GSCSI(res->cfg_entry) && 264189a36810SAnil Ravindranath masked_ioasc != PMCRAID_IOASC_HW_DEVICE_BUS_STATUS_ERROR) { 264289a36810SAnil Ravindranath pmcraid_frame_auto_sense(cmd); 264389a36810SAnil Ravindranath } 264489a36810SAnil Ravindranath 264589a36810SAnil Ravindranath /* Log IOASC/IOASA information based on user settings */ 264689a36810SAnil Ravindranath pmcraid_ioasc_logger(ioasc, cmd); 264789a36810SAnil Ravindranath 264889a36810SAnil Ravindranath switch (masked_ioasc) { 264989a36810SAnil Ravindranath 265089a36810SAnil Ravindranath case PMCRAID_IOASC_AC_TERMINATED_BY_HOST: 265189a36810SAnil Ravindranath scsi_cmd->result |= (DID_ABORT << 16); 265289a36810SAnil Ravindranath break; 265389a36810SAnil Ravindranath 265489a36810SAnil Ravindranath case PMCRAID_IOASC_IR_INVALID_RESOURCE_HANDLE: 265589a36810SAnil Ravindranath case PMCRAID_IOASC_HW_CANNOT_COMMUNICATE: 265689a36810SAnil Ravindranath scsi_cmd->result |= (DID_NO_CONNECT << 16); 265789a36810SAnil Ravindranath break; 265889a36810SAnil Ravindranath 265989a36810SAnil Ravindranath case PMCRAID_IOASC_NR_SYNC_REQUIRED: 266089a36810SAnil Ravindranath res->sync_reqd = 1; 266189a36810SAnil Ravindranath scsi_cmd->result |= (DID_IMM_RETRY << 16); 266289a36810SAnil Ravindranath break; 266389a36810SAnil Ravindranath 266489a36810SAnil Ravindranath case PMCRAID_IOASC_ME_READ_ERROR_NO_REALLOC: 266589a36810SAnil Ravindranath scsi_cmd->result |= (DID_PASSTHROUGH << 16); 266689a36810SAnil Ravindranath break; 266789a36810SAnil Ravindranath 266889a36810SAnil Ravindranath case PMCRAID_IOASC_UA_BUS_WAS_RESET: 266989a36810SAnil Ravindranath case PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER: 267089a36810SAnil Ravindranath if (!res->reset_progress) 267189a36810SAnil Ravindranath scsi_report_bus_reset(pinstance->host, 267289a36810SAnil Ravindranath scsi_cmd->device->channel); 267389a36810SAnil Ravindranath scsi_cmd->result |= (DID_ERROR << 16); 267489a36810SAnil Ravindranath break; 267589a36810SAnil Ravindranath 267689a36810SAnil Ravindranath case PMCRAID_IOASC_HW_DEVICE_BUS_STATUS_ERROR: 267789a36810SAnil Ravindranath scsi_cmd->result |= PMCRAID_IOASC_SENSE_STATUS(ioasc); 267889a36810SAnil Ravindranath res->sync_reqd = 1; 267989a36810SAnil Ravindranath 268089a36810SAnil Ravindranath /* if check_condition is not active return with error otherwise 268189a36810SAnil Ravindranath * get/frame the sense buffer 268289a36810SAnil Ravindranath */ 268389a36810SAnil Ravindranath if (PMCRAID_IOASC_SENSE_STATUS(ioasc) != 268489a36810SAnil Ravindranath SAM_STAT_CHECK_CONDITION && 268589a36810SAnil Ravindranath PMCRAID_IOASC_SENSE_STATUS(ioasc) != SAM_STAT_ACA_ACTIVE) 268689a36810SAnil Ravindranath return 0; 268789a36810SAnil Ravindranath 268889a36810SAnil Ravindranath /* If we have auto sense data as part of IOASA pass it to 268989a36810SAnil Ravindranath * mid-layer 269089a36810SAnil Ravindranath */ 269189a36810SAnil Ravindranath if (ioasa->auto_sense_length != 0) { 269245c80be6SArnd Bergmann short sense_len = le16_to_cpu(ioasa->auto_sense_length); 269345c80be6SArnd Bergmann int data_size = min_t(u16, sense_len, 269489a36810SAnil Ravindranath SCSI_SENSE_BUFFERSIZE); 269589a36810SAnil Ravindranath 269689a36810SAnil Ravindranath memcpy(scsi_cmd->sense_buffer, 269789a36810SAnil Ravindranath ioasa->sense_data, 269889a36810SAnil Ravindranath data_size); 269989a36810SAnil Ravindranath sense_copied = 1; 270089a36810SAnil Ravindranath } 270189a36810SAnil Ravindranath 2702a70757baSAnil Ravindranath if (RES_IS_GSCSI(res->cfg_entry)) 270389a36810SAnil Ravindranath pmcraid_cancel_all(cmd, sense_copied); 2704a70757baSAnil Ravindranath else if (sense_copied) 270589a36810SAnil Ravindranath pmcraid_erp_done(cmd); 2706a70757baSAnil Ravindranath else 270789a36810SAnil Ravindranath pmcraid_request_sense(cmd); 270889a36810SAnil Ravindranath 270989a36810SAnil Ravindranath return 1; 271089a36810SAnil Ravindranath 271189a36810SAnil Ravindranath case PMCRAID_IOASC_NR_INIT_CMD_REQUIRED: 271289a36810SAnil Ravindranath break; 271389a36810SAnil Ravindranath 271489a36810SAnil Ravindranath default: 271589a36810SAnil Ravindranath if (PMCRAID_IOASC_SENSE_KEY(ioasc) > RECOVERED_ERROR) 271689a36810SAnil Ravindranath scsi_cmd->result |= (DID_ERROR << 16); 271789a36810SAnil Ravindranath break; 271889a36810SAnil Ravindranath } 271989a36810SAnil Ravindranath return 0; 272089a36810SAnil Ravindranath } 272189a36810SAnil Ravindranath 272289a36810SAnil Ravindranath /** 272389a36810SAnil Ravindranath * pmcraid_reset_device - device reset handler functions 272489a36810SAnil Ravindranath * 272589a36810SAnil Ravindranath * @scsi_cmd: scsi command struct 272689a36810SAnil Ravindranath * @modifier: reset modifier indicating the reset sequence to be performed 272789a36810SAnil Ravindranath * 272889a36810SAnil Ravindranath * This function issues a device reset to the affected device. 272989a36810SAnil Ravindranath * A LUN reset will be sent to the device first. If that does 273089a36810SAnil Ravindranath * not work, a target reset will be sent. 273189a36810SAnil Ravindranath * 273289a36810SAnil Ravindranath * Return value: 273389a36810SAnil Ravindranath * SUCCESS / FAILED 273489a36810SAnil Ravindranath */ 273589a36810SAnil Ravindranath static int pmcraid_reset_device( 273689a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd, 273789a36810SAnil Ravindranath unsigned long timeout, 273889a36810SAnil Ravindranath u8 modifier 273989a36810SAnil Ravindranath ) 274089a36810SAnil Ravindranath { 274189a36810SAnil Ravindranath struct pmcraid_cmd *cmd; 274289a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 274389a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 274489a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb; 274589a36810SAnil Ravindranath unsigned long lock_flags; 274689a36810SAnil Ravindranath u32 ioasc; 274789a36810SAnil Ravindranath 274889a36810SAnil Ravindranath pinstance = 274989a36810SAnil Ravindranath (struct pmcraid_instance *)scsi_cmd->device->host->hostdata; 275089a36810SAnil Ravindranath res = scsi_cmd->device->hostdata; 275189a36810SAnil Ravindranath 275289a36810SAnil Ravindranath if (!res) { 275334876402SAnil Ravindranath sdev_printk(KERN_ERR, scsi_cmd->device, 275434876402SAnil Ravindranath "reset_device: NULL resource pointer\n"); 275589a36810SAnil Ravindranath return FAILED; 275689a36810SAnil Ravindranath } 275789a36810SAnil Ravindranath 275889a36810SAnil Ravindranath /* If adapter is currently going through reset/reload, return failed. 275989a36810SAnil Ravindranath * This will force the mid-layer to call _eh_bus/host reset, which 276089a36810SAnil Ravindranath * will then go to sleep and wait for the reset to complete 276189a36810SAnil Ravindranath */ 276289a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 276389a36810SAnil Ravindranath if (pinstance->ioa_reset_in_progress || 276489a36810SAnil Ravindranath pinstance->ioa_state == IOA_STATE_DEAD) { 276589a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 276689a36810SAnil Ravindranath return FAILED; 276789a36810SAnil Ravindranath } 276889a36810SAnil Ravindranath 276989a36810SAnil Ravindranath res->reset_progress = 1; 277089a36810SAnil Ravindranath pmcraid_info("Resetting %s resource with addr %x\n", 277189a36810SAnil Ravindranath ((modifier & RESET_DEVICE_LUN) ? "LUN" : 277289a36810SAnil Ravindranath ((modifier & RESET_DEVICE_TARGET) ? "TARGET" : "BUS")), 277389a36810SAnil Ravindranath le32_to_cpu(res->cfg_entry.resource_address)); 277489a36810SAnil Ravindranath 277589a36810SAnil Ravindranath /* get a free cmd block */ 277689a36810SAnil Ravindranath cmd = pmcraid_get_free_cmd(pinstance); 277789a36810SAnil Ravindranath 277889a36810SAnil Ravindranath if (cmd == NULL) { 277989a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 278089a36810SAnil Ravindranath pmcraid_err("%s: no cmd blocks are available\n", __func__); 278189a36810SAnil Ravindranath return FAILED; 278289a36810SAnil Ravindranath } 278389a36810SAnil Ravindranath 278489a36810SAnil Ravindranath ioarcb = &cmd->ioa_cb->ioarcb; 278589a36810SAnil Ravindranath ioarcb->resource_handle = res->cfg_entry.resource_handle; 278689a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_IOACMD; 278789a36810SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_RESET_DEVICE; 278889a36810SAnil Ravindranath 278989a36810SAnil Ravindranath /* Initialize reset modifier bits */ 279089a36810SAnil Ravindranath if (modifier) 279189a36810SAnil Ravindranath modifier = ENABLE_RESET_MODIFIER | modifier; 279289a36810SAnil Ravindranath 279389a36810SAnil Ravindranath ioarcb->cdb[1] = modifier; 279489a36810SAnil Ravindranath 279589a36810SAnil Ravindranath init_completion(&cmd->wait_for_completion); 279689a36810SAnil Ravindranath cmd->completion_req = 1; 279789a36810SAnil Ravindranath 279889a36810SAnil Ravindranath pmcraid_info("cmd(CDB[0] = %x) for %x with index = %d\n", 279989a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 280089a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioarcb.resource_handle), 280189a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle) >> 2); 280289a36810SAnil Ravindranath 280389a36810SAnil Ravindranath pmcraid_send_cmd(cmd, 280489a36810SAnil Ravindranath pmcraid_internal_done, 280589a36810SAnil Ravindranath timeout, 280689a36810SAnil Ravindranath pmcraid_timeout_handler); 280789a36810SAnil Ravindranath 280889a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 280989a36810SAnil Ravindranath 281089a36810SAnil Ravindranath /* RESET_DEVICE command completes after all pending IOARCBs are 281189a36810SAnil Ravindranath * completed. Once this command is completed, pmcraind_internal_done 281289a36810SAnil Ravindranath * will wake up the 'completion' queue. 281389a36810SAnil Ravindranath */ 281489a36810SAnil Ravindranath wait_for_completion(&cmd->wait_for_completion); 281589a36810SAnil Ravindranath 281689a36810SAnil Ravindranath /* complete the command here itself and return the command block 281789a36810SAnil Ravindranath * to free list 281889a36810SAnil Ravindranath */ 281989a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 282089a36810SAnil Ravindranath res->reset_progress = 0; 282189a36810SAnil Ravindranath ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); 282289a36810SAnil Ravindranath 282389a36810SAnil Ravindranath /* set the return value based on the returned ioasc */ 282489a36810SAnil Ravindranath return PMCRAID_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS; 282589a36810SAnil Ravindranath } 282689a36810SAnil Ravindranath 282789a36810SAnil Ravindranath /** 282889a36810SAnil Ravindranath * _pmcraid_io_done - helper for pmcraid_io_done function 282989a36810SAnil Ravindranath * 283089a36810SAnil Ravindranath * @cmd: pointer to pmcraid command struct 283189a36810SAnil Ravindranath * @reslen: residual data length to be set in the ioasa 283289a36810SAnil Ravindranath * @ioasc: ioasc either returned by IOA or set by driver itself. 283389a36810SAnil Ravindranath * 283489a36810SAnil Ravindranath * This function is invoked by pmcraid_io_done to complete mid-layer 283589a36810SAnil Ravindranath * scsi ops. 283689a36810SAnil Ravindranath * 283789a36810SAnil Ravindranath * Return value: 283889a36810SAnil Ravindranath * 0 if caller is required to return it to free_pool. Returns 1 if 283989a36810SAnil Ravindranath * caller need not worry about freeing command block as error handler 284089a36810SAnil Ravindranath * will take care of that. 284189a36810SAnil Ravindranath */ 284289a36810SAnil Ravindranath 284389a36810SAnil Ravindranath static int _pmcraid_io_done(struct pmcraid_cmd *cmd, int reslen, int ioasc) 284489a36810SAnil Ravindranath { 284589a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; 284689a36810SAnil Ravindranath int rc = 0; 284789a36810SAnil Ravindranath 284889a36810SAnil Ravindranath scsi_set_resid(scsi_cmd, reslen); 284989a36810SAnil Ravindranath 285089a36810SAnil Ravindranath pmcraid_info("response(%d) CDB[0] = %x ioasc:result: %x:%x\n", 285189a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle) >> 2, 285289a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 285389a36810SAnil Ravindranath ioasc, scsi_cmd->result); 285489a36810SAnil Ravindranath 285589a36810SAnil Ravindranath if (PMCRAID_IOASC_SENSE_KEY(ioasc) != 0) 285689a36810SAnil Ravindranath rc = pmcraid_error_handler(cmd); 285789a36810SAnil Ravindranath 285889a36810SAnil Ravindranath if (rc == 0) { 285989a36810SAnil Ravindranath scsi_dma_unmap(scsi_cmd); 286089a36810SAnil Ravindranath scsi_cmd->scsi_done(scsi_cmd); 286189a36810SAnil Ravindranath } 286289a36810SAnil Ravindranath 286389a36810SAnil Ravindranath return rc; 286489a36810SAnil Ravindranath } 286589a36810SAnil Ravindranath 286689a36810SAnil Ravindranath /** 286789a36810SAnil Ravindranath * pmcraid_io_done - SCSI completion function 286889a36810SAnil Ravindranath * 286989a36810SAnil Ravindranath * @cmd: pointer to pmcraid command struct 287089a36810SAnil Ravindranath * 287189a36810SAnil Ravindranath * This function is invoked by tasklet/mid-layer error handler to completing 287289a36810SAnil Ravindranath * the SCSI ops sent from mid-layer. 287389a36810SAnil Ravindranath * 287489a36810SAnil Ravindranath * Return value 287589a36810SAnil Ravindranath * none 287689a36810SAnil Ravindranath */ 287789a36810SAnil Ravindranath 287889a36810SAnil Ravindranath static void pmcraid_io_done(struct pmcraid_cmd *cmd) 287989a36810SAnil Ravindranath { 288089a36810SAnil Ravindranath u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); 288189a36810SAnil Ravindranath u32 reslen = le32_to_cpu(cmd->ioa_cb->ioasa.residual_data_length); 288289a36810SAnil Ravindranath 288389a36810SAnil Ravindranath if (_pmcraid_io_done(cmd, reslen, ioasc) == 0) 288489a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 288589a36810SAnil Ravindranath } 288689a36810SAnil Ravindranath 288789a36810SAnil Ravindranath /** 288889a36810SAnil Ravindranath * pmcraid_abort_cmd - Aborts a single IOARCB already submitted to IOA 288989a36810SAnil Ravindranath * 289089a36810SAnil Ravindranath * @cmd: command block of the command to be aborted 289189a36810SAnil Ravindranath * 289289a36810SAnil Ravindranath * Return Value: 289389a36810SAnil Ravindranath * returns pointer to command structure used as cancelling cmd 289489a36810SAnil Ravindranath */ 289589a36810SAnil Ravindranath static struct pmcraid_cmd *pmcraid_abort_cmd(struct pmcraid_cmd *cmd) 289689a36810SAnil Ravindranath { 289789a36810SAnil Ravindranath struct pmcraid_cmd *cancel_cmd; 289889a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 289989a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 290089a36810SAnil Ravindranath 290189a36810SAnil Ravindranath pinstance = (struct pmcraid_instance *)cmd->drv_inst; 290289a36810SAnil Ravindranath res = cmd->scsi_cmd->device->hostdata; 290389a36810SAnil Ravindranath 290489a36810SAnil Ravindranath cancel_cmd = pmcraid_get_free_cmd(pinstance); 290589a36810SAnil Ravindranath 290689a36810SAnil Ravindranath if (cancel_cmd == NULL) { 290789a36810SAnil Ravindranath pmcraid_err("%s: no cmd blocks are available\n", __func__); 290889a36810SAnil Ravindranath return NULL; 290989a36810SAnil Ravindranath } 291089a36810SAnil Ravindranath 291189a36810SAnil Ravindranath pmcraid_prepare_cancel_cmd(cancel_cmd, cmd); 291289a36810SAnil Ravindranath 291389a36810SAnil Ravindranath pmcraid_info("aborting command CDB[0]= %x with index = %d\n", 291489a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 291545c80be6SArnd Bergmann le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle) >> 2); 291689a36810SAnil Ravindranath 291789a36810SAnil Ravindranath init_completion(&cancel_cmd->wait_for_completion); 291889a36810SAnil Ravindranath cancel_cmd->completion_req = 1; 291989a36810SAnil Ravindranath 292089a36810SAnil Ravindranath pmcraid_info("command (%d) CDB[0] = %x for %x\n", 292189a36810SAnil Ravindranath le32_to_cpu(cancel_cmd->ioa_cb->ioarcb.response_handle) >> 2, 2922c20c4267SAnil Ravindranath cancel_cmd->ioa_cb->ioarcb.cdb[0], 292389a36810SAnil Ravindranath le32_to_cpu(cancel_cmd->ioa_cb->ioarcb.resource_handle)); 292489a36810SAnil Ravindranath 292589a36810SAnil Ravindranath pmcraid_send_cmd(cancel_cmd, 292689a36810SAnil Ravindranath pmcraid_internal_done, 292789a36810SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, 292889a36810SAnil Ravindranath pmcraid_timeout_handler); 292989a36810SAnil Ravindranath return cancel_cmd; 293089a36810SAnil Ravindranath } 293189a36810SAnil Ravindranath 293289a36810SAnil Ravindranath /** 293389a36810SAnil Ravindranath * pmcraid_abort_complete - Waits for ABORT TASK completion 293489a36810SAnil Ravindranath * 293589a36810SAnil Ravindranath * @cancel_cmd: command block use as cancelling command 293689a36810SAnil Ravindranath * 293789a36810SAnil Ravindranath * Return Value: 293889a36810SAnil Ravindranath * returns SUCCESS if ABORT TASK has good completion 293989a36810SAnil Ravindranath * otherwise FAILED 294089a36810SAnil Ravindranath */ 294189a36810SAnil Ravindranath static int pmcraid_abort_complete(struct pmcraid_cmd *cancel_cmd) 294289a36810SAnil Ravindranath { 294389a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 294489a36810SAnil Ravindranath u32 ioasc; 294589a36810SAnil Ravindranath 294689a36810SAnil Ravindranath wait_for_completion(&cancel_cmd->wait_for_completion); 2947c20c4267SAnil Ravindranath res = cancel_cmd->res; 2948c20c4267SAnil Ravindranath cancel_cmd->res = NULL; 294989a36810SAnil Ravindranath ioasc = le32_to_cpu(cancel_cmd->ioa_cb->ioasa.ioasc); 295089a36810SAnil Ravindranath 295189a36810SAnil Ravindranath /* If the abort task is not timed out we will get a Good completion 295289a36810SAnil Ravindranath * as sense_key, otherwise we may get one the following responses 295325985edcSLucas De Marchi * due to subsequent bus reset or device reset. In case IOASC is 295489a36810SAnil Ravindranath * NR_SYNC_REQUIRED, set sync_reqd flag for the corresponding resource 295589a36810SAnil Ravindranath */ 295689a36810SAnil Ravindranath if (ioasc == PMCRAID_IOASC_UA_BUS_WAS_RESET || 295789a36810SAnil Ravindranath ioasc == PMCRAID_IOASC_NR_SYNC_REQUIRED) { 295889a36810SAnil Ravindranath if (ioasc == PMCRAID_IOASC_NR_SYNC_REQUIRED) 295989a36810SAnil Ravindranath res->sync_reqd = 1; 296089a36810SAnil Ravindranath ioasc = 0; 296189a36810SAnil Ravindranath } 296289a36810SAnil Ravindranath 296389a36810SAnil Ravindranath /* complete the command here itself */ 296489a36810SAnil Ravindranath pmcraid_return_cmd(cancel_cmd); 296589a36810SAnil Ravindranath return PMCRAID_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS; 296689a36810SAnil Ravindranath } 296789a36810SAnil Ravindranath 296889a36810SAnil Ravindranath /** 296989a36810SAnil Ravindranath * pmcraid_eh_abort_handler - entry point for aborting a single task on errors 297089a36810SAnil Ravindranath * 297189a36810SAnil Ravindranath * @scsi_cmd: scsi command struct given by mid-layer. When this is called 297289a36810SAnil Ravindranath * mid-layer ensures that no other commands are queued. This 297389a36810SAnil Ravindranath * never gets called under interrupt, but a separate eh thread. 297489a36810SAnil Ravindranath * 297589a36810SAnil Ravindranath * Return value: 297689a36810SAnil Ravindranath * SUCCESS / FAILED 297789a36810SAnil Ravindranath */ 297889a36810SAnil Ravindranath static int pmcraid_eh_abort_handler(struct scsi_cmnd *scsi_cmd) 297989a36810SAnil Ravindranath { 298089a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 298189a36810SAnil Ravindranath struct pmcraid_cmd *cmd; 298289a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 298389a36810SAnil Ravindranath unsigned long host_lock_flags; 298489a36810SAnil Ravindranath unsigned long pending_lock_flags; 298589a36810SAnil Ravindranath struct pmcraid_cmd *cancel_cmd = NULL; 298689a36810SAnil Ravindranath int cmd_found = 0; 298789a36810SAnil Ravindranath int rc = FAILED; 298889a36810SAnil Ravindranath 298989a36810SAnil Ravindranath pinstance = 299089a36810SAnil Ravindranath (struct pmcraid_instance *)scsi_cmd->device->host->hostdata; 299189a36810SAnil Ravindranath 299234876402SAnil Ravindranath scmd_printk(KERN_INFO, scsi_cmd, 299389a36810SAnil Ravindranath "I/O command timed out, aborting it.\n"); 299489a36810SAnil Ravindranath 299589a36810SAnil Ravindranath res = scsi_cmd->device->hostdata; 299689a36810SAnil Ravindranath 299789a36810SAnil Ravindranath if (res == NULL) 299889a36810SAnil Ravindranath return rc; 299989a36810SAnil Ravindranath 300089a36810SAnil Ravindranath /* If we are currently going through reset/reload, return failed. 300189a36810SAnil Ravindranath * This will force the mid-layer to eventually call 300289a36810SAnil Ravindranath * pmcraid_eh_host_reset which will then go to sleep and wait for the 300389a36810SAnil Ravindranath * reset to complete 300489a36810SAnil Ravindranath */ 300589a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, host_lock_flags); 300689a36810SAnil Ravindranath 300789a36810SAnil Ravindranath if (pinstance->ioa_reset_in_progress || 300889a36810SAnil Ravindranath pinstance->ioa_state == IOA_STATE_DEAD) { 300989a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 301089a36810SAnil Ravindranath host_lock_flags); 301189a36810SAnil Ravindranath return rc; 301289a36810SAnil Ravindranath } 301389a36810SAnil Ravindranath 301489a36810SAnil Ravindranath /* loop over pending cmd list to find cmd corresponding to this 301589a36810SAnil Ravindranath * scsi_cmd. Note that this command might not have been completed 301689a36810SAnil Ravindranath * already. locking: all pending commands are protected with 301789a36810SAnil Ravindranath * pending_pool_lock. 301889a36810SAnil Ravindranath */ 301989a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->pending_pool_lock, pending_lock_flags); 302089a36810SAnil Ravindranath list_for_each_entry(cmd, &pinstance->pending_cmd_pool, free_list) { 302189a36810SAnil Ravindranath 302289a36810SAnil Ravindranath if (cmd->scsi_cmd == scsi_cmd) { 302389a36810SAnil Ravindranath cmd_found = 1; 302489a36810SAnil Ravindranath break; 302589a36810SAnil Ravindranath } 302689a36810SAnil Ravindranath } 302789a36810SAnil Ravindranath 302889a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->pending_pool_lock, 302989a36810SAnil Ravindranath pending_lock_flags); 303089a36810SAnil Ravindranath 303189a36810SAnil Ravindranath /* If the command to be aborted was given to IOA and still pending with 303289a36810SAnil Ravindranath * it, send ABORT_TASK to abort this and wait for its completion 303389a36810SAnil Ravindranath */ 303489a36810SAnil Ravindranath if (cmd_found) 303589a36810SAnil Ravindranath cancel_cmd = pmcraid_abort_cmd(cmd); 303689a36810SAnil Ravindranath 303789a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 303889a36810SAnil Ravindranath host_lock_flags); 303989a36810SAnil Ravindranath 304089a36810SAnil Ravindranath if (cancel_cmd) { 3041c20c4267SAnil Ravindranath cancel_cmd->res = cmd->scsi_cmd->device->hostdata; 304289a36810SAnil Ravindranath rc = pmcraid_abort_complete(cancel_cmd); 304389a36810SAnil Ravindranath } 304489a36810SAnil Ravindranath 304589a36810SAnil Ravindranath return cmd_found ? rc : SUCCESS; 304689a36810SAnil Ravindranath } 304789a36810SAnil Ravindranath 304889a36810SAnil Ravindranath /** 304989a36810SAnil Ravindranath * pmcraid_eh_xxxx_reset_handler - bus/target/device reset handler callbacks 305089a36810SAnil Ravindranath * 305189a36810SAnil Ravindranath * @scmd: pointer to scsi_cmd that was sent to the resource to be reset. 305289a36810SAnil Ravindranath * 305389a36810SAnil Ravindranath * All these routines invokve pmcraid_reset_device with appropriate parameters. 305489a36810SAnil Ravindranath * Since these are called from mid-layer EH thread, no other IO will be queued 305589a36810SAnil Ravindranath * to the resource being reset. However, control path (IOCTL) may be active so 305689a36810SAnil Ravindranath * it is necessary to synchronize IOARRIN writes which pmcraid_reset_device 305789a36810SAnil Ravindranath * takes care by locking/unlocking host_lock. 305889a36810SAnil Ravindranath * 305989a36810SAnil Ravindranath * Return value 306089a36810SAnil Ravindranath * SUCCESS or FAILED 306189a36810SAnil Ravindranath */ 306289a36810SAnil Ravindranath static int pmcraid_eh_device_reset_handler(struct scsi_cmnd *scmd) 306389a36810SAnil Ravindranath { 306434876402SAnil Ravindranath scmd_printk(KERN_INFO, scmd, 306534876402SAnil Ravindranath "resetting device due to an I/O command timeout.\n"); 306689a36810SAnil Ravindranath return pmcraid_reset_device(scmd, 306789a36810SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, 306889a36810SAnil Ravindranath RESET_DEVICE_LUN); 306989a36810SAnil Ravindranath } 307089a36810SAnil Ravindranath 307189a36810SAnil Ravindranath static int pmcraid_eh_bus_reset_handler(struct scsi_cmnd *scmd) 307289a36810SAnil Ravindranath { 307334876402SAnil Ravindranath scmd_printk(KERN_INFO, scmd, 307434876402SAnil Ravindranath "Doing bus reset due to an I/O command timeout.\n"); 307589a36810SAnil Ravindranath return pmcraid_reset_device(scmd, 307689a36810SAnil Ravindranath PMCRAID_RESET_BUS_TIMEOUT, 307789a36810SAnil Ravindranath RESET_DEVICE_BUS); 307889a36810SAnil Ravindranath } 307989a36810SAnil Ravindranath 308089a36810SAnil Ravindranath static int pmcraid_eh_target_reset_handler(struct scsi_cmnd *scmd) 308189a36810SAnil Ravindranath { 308234876402SAnil Ravindranath scmd_printk(KERN_INFO, scmd, 308334876402SAnil Ravindranath "Doing target reset due to an I/O command timeout.\n"); 308489a36810SAnil Ravindranath return pmcraid_reset_device(scmd, 308589a36810SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, 308689a36810SAnil Ravindranath RESET_DEVICE_TARGET); 308789a36810SAnil Ravindranath } 308889a36810SAnil Ravindranath 308989a36810SAnil Ravindranath /** 309089a36810SAnil Ravindranath * pmcraid_eh_host_reset_handler - adapter reset handler callback 309189a36810SAnil Ravindranath * 309289a36810SAnil Ravindranath * @scmd: pointer to scsi_cmd that was sent to a resource of adapter 309389a36810SAnil Ravindranath * 309489a36810SAnil Ravindranath * Initiates adapter reset to bring it up to operational state 309589a36810SAnil Ravindranath * 309689a36810SAnil Ravindranath * Return value 309789a36810SAnil Ravindranath * SUCCESS or FAILED 309889a36810SAnil Ravindranath */ 309989a36810SAnil Ravindranath static int pmcraid_eh_host_reset_handler(struct scsi_cmnd *scmd) 310089a36810SAnil Ravindranath { 310189a36810SAnil Ravindranath unsigned long interval = 10000; /* 10 seconds interval */ 310289a36810SAnil Ravindranath int waits = jiffies_to_msecs(PMCRAID_RESET_HOST_TIMEOUT) / interval; 310389a36810SAnil Ravindranath struct pmcraid_instance *pinstance = 310489a36810SAnil Ravindranath (struct pmcraid_instance *)(scmd->device->host->hostdata); 310589a36810SAnil Ravindranath 310689a36810SAnil Ravindranath 310789a36810SAnil Ravindranath /* wait for an additional 150 seconds just in case firmware could come 310889a36810SAnil Ravindranath * up and if it could complete all the pending commands excluding the 310989a36810SAnil Ravindranath * two HCAM (CCN and LDN). 311089a36810SAnil Ravindranath */ 311189a36810SAnil Ravindranath while (waits--) { 311289a36810SAnil Ravindranath if (atomic_read(&pinstance->outstanding_cmds) <= 311389a36810SAnil Ravindranath PMCRAID_MAX_HCAM_CMD) 311489a36810SAnil Ravindranath return SUCCESS; 311589a36810SAnil Ravindranath msleep(interval); 311689a36810SAnil Ravindranath } 311789a36810SAnil Ravindranath 311889a36810SAnil Ravindranath dev_err(&pinstance->pdev->dev, 311989a36810SAnil Ravindranath "Adapter being reset due to an I/O command timeout.\n"); 312089a36810SAnil Ravindranath return pmcraid_reset_bringup(pinstance) == 0 ? SUCCESS : FAILED; 312189a36810SAnil Ravindranath } 312289a36810SAnil Ravindranath 312389a36810SAnil Ravindranath /** 312489a36810SAnil Ravindranath * pmcraid_init_ioadls - initializes IOADL related fields in IOARCB 312589a36810SAnil Ravindranath * @cmd: pmcraid command struct 312689a36810SAnil Ravindranath * @sgcount: count of scatter-gather elements 312789a36810SAnil Ravindranath * 312889a36810SAnil Ravindranath * Return value 312989a36810SAnil Ravindranath * returns pointer pmcraid_ioadl_desc, initialized to point to internal 313089a36810SAnil Ravindranath * or external IOADLs 313189a36810SAnil Ravindranath */ 313261b96d5bSBaoyou Xie static struct pmcraid_ioadl_desc * 313389a36810SAnil Ravindranath pmcraid_init_ioadls(struct pmcraid_cmd *cmd, int sgcount) 313489a36810SAnil Ravindranath { 313589a36810SAnil Ravindranath struct pmcraid_ioadl_desc *ioadl; 313689a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 313789a36810SAnil Ravindranath int ioadl_count = 0; 313889a36810SAnil Ravindranath 313989a36810SAnil Ravindranath if (ioarcb->add_cmd_param_length) 314045c80be6SArnd Bergmann ioadl_count = DIV_ROUND_UP(le16_to_cpu(ioarcb->add_cmd_param_length), 16); 314145c80be6SArnd Bergmann ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc) * sgcount); 314289a36810SAnil Ravindranath 314389a36810SAnil Ravindranath if ((sgcount + ioadl_count) > (ARRAY_SIZE(ioarcb->add_data.u.ioadl))) { 314489a36810SAnil Ravindranath /* external ioadls start at offset 0x80 from control_block 314589a36810SAnil Ravindranath * structure, re-using 24 out of 27 ioadls part of IOARCB. 314689a36810SAnil Ravindranath * It is necessary to indicate to firmware that driver is 314789a36810SAnil Ravindranath * using ioadls to be treated as external to IOARCB. 314889a36810SAnil Ravindranath */ 314945c80be6SArnd Bergmann ioarcb->ioarcb_bus_addr &= cpu_to_le64(~(0x1FULL)); 315089a36810SAnil Ravindranath ioarcb->ioadl_bus_addr = 315189a36810SAnil Ravindranath cpu_to_le64((cmd->ioa_cb_bus_addr) + 315289a36810SAnil Ravindranath offsetof(struct pmcraid_ioarcb, 315389a36810SAnil Ravindranath add_data.u.ioadl[3])); 315489a36810SAnil Ravindranath ioadl = &ioarcb->add_data.u.ioadl[3]; 315589a36810SAnil Ravindranath } else { 315689a36810SAnil Ravindranath ioarcb->ioadl_bus_addr = 315789a36810SAnil Ravindranath cpu_to_le64((cmd->ioa_cb_bus_addr) + 315889a36810SAnil Ravindranath offsetof(struct pmcraid_ioarcb, 315989a36810SAnil Ravindranath add_data.u.ioadl[ioadl_count])); 316089a36810SAnil Ravindranath 316189a36810SAnil Ravindranath ioadl = &ioarcb->add_data.u.ioadl[ioadl_count]; 316289a36810SAnil Ravindranath ioarcb->ioarcb_bus_addr |= 316345c80be6SArnd Bergmann cpu_to_le64(DIV_ROUND_CLOSEST(sgcount + ioadl_count, 8)); 316489a36810SAnil Ravindranath } 316589a36810SAnil Ravindranath 316689a36810SAnil Ravindranath return ioadl; 316789a36810SAnil Ravindranath } 316889a36810SAnil Ravindranath 316989a36810SAnil Ravindranath /** 317089a36810SAnil Ravindranath * pmcraid_build_ioadl - Build a scatter/gather list and map the buffer 317189a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 317289a36810SAnil Ravindranath * @cmd: pmcraid command struct 317389a36810SAnil Ravindranath * 317489a36810SAnil Ravindranath * This function is invoked by queuecommand entry point while sending a command 317589a36810SAnil Ravindranath * to firmware. This builds ioadl descriptors and sets up ioarcb fields. 317689a36810SAnil Ravindranath * 317789a36810SAnil Ravindranath * Return value: 317889a36810SAnil Ravindranath * 0 on success or -1 on failure 317989a36810SAnil Ravindranath */ 318089a36810SAnil Ravindranath static int pmcraid_build_ioadl( 318189a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 318289a36810SAnil Ravindranath struct pmcraid_cmd *cmd 318389a36810SAnil Ravindranath ) 318489a36810SAnil Ravindranath { 318589a36810SAnil Ravindranath int i, nseg; 318689a36810SAnil Ravindranath struct scatterlist *sglist; 318789a36810SAnil Ravindranath 318889a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; 318989a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &(cmd->ioa_cb->ioarcb); 319089a36810SAnil Ravindranath struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; 319189a36810SAnil Ravindranath 319289a36810SAnil Ravindranath u32 length = scsi_bufflen(scsi_cmd); 319389a36810SAnil Ravindranath 319489a36810SAnil Ravindranath if (!length) 319589a36810SAnil Ravindranath return 0; 319689a36810SAnil Ravindranath 319789a36810SAnil Ravindranath nseg = scsi_dma_map(scsi_cmd); 319889a36810SAnil Ravindranath 319989a36810SAnil Ravindranath if (nseg < 0) { 320034876402SAnil Ravindranath scmd_printk(KERN_ERR, scsi_cmd, "scsi_map_dma failed!\n"); 320189a36810SAnil Ravindranath return -1; 320289a36810SAnil Ravindranath } else if (nseg > PMCRAID_MAX_IOADLS) { 320389a36810SAnil Ravindranath scsi_dma_unmap(scsi_cmd); 320434876402SAnil Ravindranath scmd_printk(KERN_ERR, scsi_cmd, 320589a36810SAnil Ravindranath "sg count is (%d) more than allowed!\n", nseg); 320689a36810SAnil Ravindranath return -1; 320789a36810SAnil Ravindranath } 320889a36810SAnil Ravindranath 320989a36810SAnil Ravindranath /* Initialize IOARCB data transfer length fields */ 321089a36810SAnil Ravindranath if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) 321189a36810SAnil Ravindranath ioarcb->request_flags0 |= TRANSFER_DIR_WRITE; 321289a36810SAnil Ravindranath 321389a36810SAnil Ravindranath ioarcb->request_flags0 |= NO_LINK_DESCS; 321489a36810SAnil Ravindranath ioarcb->data_transfer_length = cpu_to_le32(length); 321589a36810SAnil Ravindranath ioadl = pmcraid_init_ioadls(cmd, nseg); 321689a36810SAnil Ravindranath 321789a36810SAnil Ravindranath /* Initialize IOADL descriptor addresses */ 321889a36810SAnil Ravindranath scsi_for_each_sg(scsi_cmd, sglist, nseg, i) { 321989a36810SAnil Ravindranath ioadl[i].data_len = cpu_to_le32(sg_dma_len(sglist)); 322089a36810SAnil Ravindranath ioadl[i].address = cpu_to_le64(sg_dma_address(sglist)); 322189a36810SAnil Ravindranath ioadl[i].flags = 0; 322289a36810SAnil Ravindranath } 322389a36810SAnil Ravindranath /* setup last descriptor */ 322488197966SAnil Ravindranath ioadl[i - 1].flags = IOADL_FLAGS_LAST_DESC; 322589a36810SAnil Ravindranath 322689a36810SAnil Ravindranath return 0; 322789a36810SAnil Ravindranath } 322889a36810SAnil Ravindranath 322989a36810SAnil Ravindranath /** 323089a36810SAnil Ravindranath * pmcraid_free_sglist - Frees an allocated SG buffer list 323189a36810SAnil Ravindranath * @sglist: scatter/gather list pointer 323289a36810SAnil Ravindranath * 323389a36810SAnil Ravindranath * Free a DMA'able memory previously allocated with pmcraid_alloc_sglist 323489a36810SAnil Ravindranath * 323589a36810SAnil Ravindranath * Return value: 323689a36810SAnil Ravindranath * none 323789a36810SAnil Ravindranath */ 323889a36810SAnil Ravindranath static void pmcraid_free_sglist(struct pmcraid_sglist *sglist) 323989a36810SAnil Ravindranath { 324089a36810SAnil Ravindranath int i; 324189a36810SAnil Ravindranath 324289a36810SAnil Ravindranath for (i = 0; i < sglist->num_sg; i++) 324389a36810SAnil Ravindranath __free_pages(sg_page(&(sglist->scatterlist[i])), 324489a36810SAnil Ravindranath sglist->order); 324589a36810SAnil Ravindranath 324689a36810SAnil Ravindranath kfree(sglist); 324789a36810SAnil Ravindranath } 324889a36810SAnil Ravindranath 324989a36810SAnil Ravindranath /** 325089a36810SAnil Ravindranath * pmcraid_alloc_sglist - Allocates memory for a SG list 325189a36810SAnil Ravindranath * @buflen: buffer length 325289a36810SAnil Ravindranath * 325389a36810SAnil Ravindranath * Allocates a DMA'able buffer in chunks and assembles a scatter/gather 325489a36810SAnil Ravindranath * list. 325589a36810SAnil Ravindranath * 325689a36810SAnil Ravindranath * Return value 325789a36810SAnil Ravindranath * pointer to sglist / NULL on failure 325889a36810SAnil Ravindranath */ 325989a36810SAnil Ravindranath static struct pmcraid_sglist *pmcraid_alloc_sglist(int buflen) 326089a36810SAnil Ravindranath { 326189a36810SAnil Ravindranath struct pmcraid_sglist *sglist; 326289a36810SAnil Ravindranath struct scatterlist *scatterlist; 326389a36810SAnil Ravindranath struct page *page; 326489a36810SAnil Ravindranath int num_elem, i, j; 326589a36810SAnil Ravindranath int sg_size; 326689a36810SAnil Ravindranath int order; 326789a36810SAnil Ravindranath int bsize_elem; 326889a36810SAnil Ravindranath 326989a36810SAnil Ravindranath sg_size = buflen / (PMCRAID_MAX_IOADLS - 1); 327089a36810SAnil Ravindranath order = (sg_size > 0) ? get_order(sg_size) : 0; 327189a36810SAnil Ravindranath bsize_elem = PAGE_SIZE * (1 << order); 327289a36810SAnil Ravindranath 327389a36810SAnil Ravindranath /* Determine the actual number of sg entries needed */ 327489a36810SAnil Ravindranath if (buflen % bsize_elem) 327589a36810SAnil Ravindranath num_elem = (buflen / bsize_elem) + 1; 327689a36810SAnil Ravindranath else 327789a36810SAnil Ravindranath num_elem = buflen / bsize_elem; 327889a36810SAnil Ravindranath 327989a36810SAnil Ravindranath /* Allocate a scatter/gather list for the DMA */ 328089a36810SAnil Ravindranath sglist = kzalloc(sizeof(struct pmcraid_sglist) + 328189a36810SAnil Ravindranath (sizeof(struct scatterlist) * (num_elem - 1)), 328289a36810SAnil Ravindranath GFP_KERNEL); 328389a36810SAnil Ravindranath 328489a36810SAnil Ravindranath if (sglist == NULL) 328589a36810SAnil Ravindranath return NULL; 328689a36810SAnil Ravindranath 328789a36810SAnil Ravindranath scatterlist = sglist->scatterlist; 328889a36810SAnil Ravindranath sg_init_table(scatterlist, num_elem); 328989a36810SAnil Ravindranath sglist->order = order; 329089a36810SAnil Ravindranath sglist->num_sg = num_elem; 329189a36810SAnil Ravindranath sg_size = buflen; 329289a36810SAnil Ravindranath 329389a36810SAnil Ravindranath for (i = 0; i < num_elem; i++) { 3294592488a3SAnil Ravindranath page = alloc_pages(GFP_KERNEL|GFP_DMA|__GFP_ZERO, order); 329589a36810SAnil Ravindranath if (!page) { 329689a36810SAnil Ravindranath for (j = i - 1; j >= 0; j--) 329789a36810SAnil Ravindranath __free_pages(sg_page(&scatterlist[j]), order); 329889a36810SAnil Ravindranath kfree(sglist); 329989a36810SAnil Ravindranath return NULL; 330089a36810SAnil Ravindranath } 330189a36810SAnil Ravindranath 330289a36810SAnil Ravindranath sg_set_page(&scatterlist[i], page, 330389a36810SAnil Ravindranath sg_size < bsize_elem ? sg_size : bsize_elem, 0); 330489a36810SAnil Ravindranath sg_size -= bsize_elem; 330589a36810SAnil Ravindranath } 330689a36810SAnil Ravindranath 330789a36810SAnil Ravindranath return sglist; 330889a36810SAnil Ravindranath } 330989a36810SAnil Ravindranath 331089a36810SAnil Ravindranath /** 331189a36810SAnil Ravindranath * pmcraid_copy_sglist - Copy user buffer to kernel buffer's SG list 331289a36810SAnil Ravindranath * @sglist: scatter/gather list pointer 331389a36810SAnil Ravindranath * @buffer: buffer pointer 331489a36810SAnil Ravindranath * @len: buffer length 331589a36810SAnil Ravindranath * @direction: data transfer direction 331689a36810SAnil Ravindranath * 331789a36810SAnil Ravindranath * Copy a user buffer into a buffer allocated by pmcraid_alloc_sglist 331889a36810SAnil Ravindranath * 331989a36810SAnil Ravindranath * Return value: 332089a36810SAnil Ravindranath * 0 on success / other on failure 332189a36810SAnil Ravindranath */ 332289a36810SAnil Ravindranath static int pmcraid_copy_sglist( 332389a36810SAnil Ravindranath struct pmcraid_sglist *sglist, 33243397623bSArnd Bergmann void __user *buffer, 332589a36810SAnil Ravindranath u32 len, 332689a36810SAnil Ravindranath int direction 332789a36810SAnil Ravindranath ) 332889a36810SAnil Ravindranath { 332989a36810SAnil Ravindranath struct scatterlist *scatterlist; 333089a36810SAnil Ravindranath void *kaddr; 333189a36810SAnil Ravindranath int bsize_elem; 333289a36810SAnil Ravindranath int i; 333389a36810SAnil Ravindranath int rc = 0; 333489a36810SAnil Ravindranath 333589a36810SAnil Ravindranath /* Determine the actual number of bytes per element */ 333689a36810SAnil Ravindranath bsize_elem = PAGE_SIZE * (1 << sglist->order); 333789a36810SAnil Ravindranath 333889a36810SAnil Ravindranath scatterlist = sglist->scatterlist; 333989a36810SAnil Ravindranath 334089a36810SAnil Ravindranath for (i = 0; i < (len / bsize_elem); i++, buffer += bsize_elem) { 334189a36810SAnil Ravindranath struct page *page = sg_page(&scatterlist[i]); 334289a36810SAnil Ravindranath 334389a36810SAnil Ravindranath kaddr = kmap(page); 334489a36810SAnil Ravindranath if (direction == DMA_TO_DEVICE) 33453397623bSArnd Bergmann rc = __copy_from_user(kaddr, buffer, bsize_elem); 334689a36810SAnil Ravindranath else 33473397623bSArnd Bergmann rc = __copy_to_user(buffer, kaddr, bsize_elem); 334889a36810SAnil Ravindranath 334989a36810SAnil Ravindranath kunmap(page); 335089a36810SAnil Ravindranath 335189a36810SAnil Ravindranath if (rc) { 335289a36810SAnil Ravindranath pmcraid_err("failed to copy user data into sg list\n"); 335389a36810SAnil Ravindranath return -EFAULT; 335489a36810SAnil Ravindranath } 335589a36810SAnil Ravindranath 335689a36810SAnil Ravindranath scatterlist[i].length = bsize_elem; 335789a36810SAnil Ravindranath } 335889a36810SAnil Ravindranath 335989a36810SAnil Ravindranath if (len % bsize_elem) { 336089a36810SAnil Ravindranath struct page *page = sg_page(&scatterlist[i]); 336189a36810SAnil Ravindranath 336289a36810SAnil Ravindranath kaddr = kmap(page); 336389a36810SAnil Ravindranath 336489a36810SAnil Ravindranath if (direction == DMA_TO_DEVICE) 33653397623bSArnd Bergmann rc = __copy_from_user(kaddr, buffer, len % bsize_elem); 336689a36810SAnil Ravindranath else 33673397623bSArnd Bergmann rc = __copy_to_user(buffer, kaddr, len % bsize_elem); 336889a36810SAnil Ravindranath 336989a36810SAnil Ravindranath kunmap(page); 337089a36810SAnil Ravindranath 337189a36810SAnil Ravindranath scatterlist[i].length = len % bsize_elem; 337289a36810SAnil Ravindranath } 337389a36810SAnil Ravindranath 337489a36810SAnil Ravindranath if (rc) { 337589a36810SAnil Ravindranath pmcraid_err("failed to copy user data into sg list\n"); 337689a36810SAnil Ravindranath rc = -EFAULT; 337789a36810SAnil Ravindranath } 337889a36810SAnil Ravindranath 337989a36810SAnil Ravindranath return rc; 338089a36810SAnil Ravindranath } 338189a36810SAnil Ravindranath 338289a36810SAnil Ravindranath /** 338389a36810SAnil Ravindranath * pmcraid_queuecommand - Queue a mid-layer request 338489a36810SAnil Ravindranath * @scsi_cmd: scsi command struct 338589a36810SAnil Ravindranath * @done: done function 338689a36810SAnil Ravindranath * 338789a36810SAnil Ravindranath * This function queues a request generated by the mid-layer. Midlayer calls 338889a36810SAnil Ravindranath * this routine within host->lock. Some of the functions called by queuecommand 338989a36810SAnil Ravindranath * would use cmd block queue locks (free_pool_lock and pending_pool_lock) 339089a36810SAnil Ravindranath * 339189a36810SAnil Ravindranath * Return value: 339289a36810SAnil Ravindranath * 0 on success 339389a36810SAnil Ravindranath * SCSI_MLQUEUE_DEVICE_BUSY if device is busy 339489a36810SAnil Ravindranath * SCSI_MLQUEUE_HOST_BUSY if host is busy 339589a36810SAnil Ravindranath */ 3396f281233dSJeff Garzik static int pmcraid_queuecommand_lck( 339789a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd, 339889a36810SAnil Ravindranath void (*done) (struct scsi_cmnd *) 339989a36810SAnil Ravindranath ) 340089a36810SAnil Ravindranath { 340189a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 340289a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 340389a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb; 340489a36810SAnil Ravindranath struct pmcraid_cmd *cmd; 3405c20c4267SAnil Ravindranath u32 fw_version; 340689a36810SAnil Ravindranath int rc = 0; 340789a36810SAnil Ravindranath 340889a36810SAnil Ravindranath pinstance = 340989a36810SAnil Ravindranath (struct pmcraid_instance *)scsi_cmd->device->host->hostdata; 3410c20c4267SAnil Ravindranath fw_version = be16_to_cpu(pinstance->inq_data->fw_version); 341189a36810SAnil Ravindranath scsi_cmd->scsi_done = done; 341289a36810SAnil Ravindranath res = scsi_cmd->device->hostdata; 341389a36810SAnil Ravindranath scsi_cmd->result = (DID_OK << 16); 341489a36810SAnil Ravindranath 341589a36810SAnil Ravindranath /* if adapter is marked as dead, set result to DID_NO_CONNECT complete 341689a36810SAnil Ravindranath * the command 341789a36810SAnil Ravindranath */ 341889a36810SAnil Ravindranath if (pinstance->ioa_state == IOA_STATE_DEAD) { 341989a36810SAnil Ravindranath pmcraid_info("IOA is dead, but queuecommand is scheduled\n"); 342089a36810SAnil Ravindranath scsi_cmd->result = (DID_NO_CONNECT << 16); 342189a36810SAnil Ravindranath scsi_cmd->scsi_done(scsi_cmd); 342289a36810SAnil Ravindranath return 0; 342389a36810SAnil Ravindranath } 342489a36810SAnil Ravindranath 342589a36810SAnil Ravindranath /* If IOA reset is in progress, can't queue the commands */ 342689a36810SAnil Ravindranath if (pinstance->ioa_reset_in_progress) 342789a36810SAnil Ravindranath return SCSI_MLQUEUE_HOST_BUSY; 342889a36810SAnil Ravindranath 3429c20c4267SAnil Ravindranath /* Firmware doesn't support SYNCHRONIZE_CACHE command (0x35), complete 3430c20c4267SAnil Ravindranath * the command here itself with success return 3431c20c4267SAnil Ravindranath */ 3432c20c4267SAnil Ravindranath if (scsi_cmd->cmnd[0] == SYNCHRONIZE_CACHE) { 3433c20c4267SAnil Ravindranath pmcraid_info("SYNC_CACHE(0x35), completing in driver itself\n"); 3434c20c4267SAnil Ravindranath scsi_cmd->scsi_done(scsi_cmd); 3435c20c4267SAnil Ravindranath return 0; 3436c20c4267SAnil Ravindranath } 3437c20c4267SAnil Ravindranath 343889a36810SAnil Ravindranath /* initialize the command and IOARCB to be sent to IOA */ 343989a36810SAnil Ravindranath cmd = pmcraid_get_free_cmd(pinstance); 344089a36810SAnil Ravindranath 344189a36810SAnil Ravindranath if (cmd == NULL) { 344289a36810SAnil Ravindranath pmcraid_err("free command block is not available\n"); 344389a36810SAnil Ravindranath return SCSI_MLQUEUE_HOST_BUSY; 344489a36810SAnil Ravindranath } 344589a36810SAnil Ravindranath 344689a36810SAnil Ravindranath cmd->scsi_cmd = scsi_cmd; 344789a36810SAnil Ravindranath ioarcb = &(cmd->ioa_cb->ioarcb); 344889a36810SAnil Ravindranath memcpy(ioarcb->cdb, scsi_cmd->cmnd, scsi_cmd->cmd_len); 344989a36810SAnil Ravindranath ioarcb->resource_handle = res->cfg_entry.resource_handle; 345089a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_SCSI; 345189a36810SAnil Ravindranath 3452c20c4267SAnil Ravindranath /* set hrrq number where the IOA should respond to. Note that all cmds 3453c20c4267SAnil Ravindranath * generated internally uses hrrq_id 0, exception to this is the cmd 3454c20c4267SAnil Ravindranath * block of scsi_cmd which is re-used (e.g. cancel/abort), which uses 3455c20c4267SAnil Ravindranath * hrrq_id assigned here in queuecommand 3456c20c4267SAnil Ravindranath */ 3457c20c4267SAnil Ravindranath ioarcb->hrrq_id = atomic_add_return(1, &(pinstance->last_message_id)) % 3458c20c4267SAnil Ravindranath pinstance->num_hrrq; 345989a36810SAnil Ravindranath cmd->cmd_done = pmcraid_io_done; 346089a36810SAnil Ravindranath 346189a36810SAnil Ravindranath if (RES_IS_GSCSI(res->cfg_entry) || RES_IS_VSET(res->cfg_entry)) { 346289a36810SAnil Ravindranath if (scsi_cmd->underflow == 0) 346389a36810SAnil Ravindranath ioarcb->request_flags0 |= INHIBIT_UL_CHECK; 346489a36810SAnil Ravindranath 346589a36810SAnil Ravindranath if (res->sync_reqd) { 346689a36810SAnil Ravindranath ioarcb->request_flags0 |= SYNC_COMPLETE; 346789a36810SAnil Ravindranath res->sync_reqd = 0; 346889a36810SAnil Ravindranath } 346989a36810SAnil Ravindranath 347089a36810SAnil Ravindranath ioarcb->request_flags0 |= NO_LINK_DESCS; 347150668633SChristoph Hellwig 347250668633SChristoph Hellwig if (scsi_cmd->flags & SCMD_TAGGED) 347350668633SChristoph Hellwig ioarcb->request_flags1 |= TASK_TAG_SIMPLE; 347489a36810SAnil Ravindranath 347589a36810SAnil Ravindranath if (RES_IS_GSCSI(res->cfg_entry)) 347689a36810SAnil Ravindranath ioarcb->request_flags1 |= DELAY_AFTER_RESET; 347789a36810SAnil Ravindranath } 347889a36810SAnil Ravindranath 347989a36810SAnil Ravindranath rc = pmcraid_build_ioadl(pinstance, cmd); 348089a36810SAnil Ravindranath 348189a36810SAnil Ravindranath pmcraid_info("command (%d) CDB[0] = %x for %x:%x:%x:%x\n", 348289a36810SAnil Ravindranath le32_to_cpu(ioarcb->response_handle) >> 2, 348389a36810SAnil Ravindranath scsi_cmd->cmnd[0], pinstance->host->unique_id, 348489a36810SAnil Ravindranath RES_IS_VSET(res->cfg_entry) ? PMCRAID_VSET_BUS_ID : 348589a36810SAnil Ravindranath PMCRAID_PHYS_BUS_ID, 348689a36810SAnil Ravindranath RES_IS_VSET(res->cfg_entry) ? 3487c20c4267SAnil Ravindranath (fw_version <= PMCRAID_FW_VERSION_1 ? 348889a36810SAnil Ravindranath res->cfg_entry.unique_flags1 : 348945c80be6SArnd Bergmann le16_to_cpu(res->cfg_entry.array_id) & 0xFF) : 349089a36810SAnil Ravindranath RES_TARGET(res->cfg_entry.resource_address), 349189a36810SAnil Ravindranath RES_LUN(res->cfg_entry.resource_address)); 349289a36810SAnil Ravindranath 349389a36810SAnil Ravindranath if (likely(rc == 0)) { 349489a36810SAnil Ravindranath _pmcraid_fire_command(cmd); 349589a36810SAnil Ravindranath } else { 349689a36810SAnil Ravindranath pmcraid_err("queuecommand could not build ioadl\n"); 349789a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 349889a36810SAnil Ravindranath rc = SCSI_MLQUEUE_HOST_BUSY; 349989a36810SAnil Ravindranath } 350089a36810SAnil Ravindranath 350189a36810SAnil Ravindranath return rc; 350289a36810SAnil Ravindranath } 350389a36810SAnil Ravindranath 3504f281233dSJeff Garzik static DEF_SCSI_QCMD(pmcraid_queuecommand) 3505f281233dSJeff Garzik 350689a36810SAnil Ravindranath /** 350789a36810SAnil Ravindranath * pmcraid_open -char node "open" entry, allowed only users with admin access 350889a36810SAnil Ravindranath */ 350989a36810SAnil Ravindranath static int pmcraid_chr_open(struct inode *inode, struct file *filep) 351089a36810SAnil Ravindranath { 351189a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 351289a36810SAnil Ravindranath 351389a36810SAnil Ravindranath if (!capable(CAP_SYS_ADMIN)) 351489a36810SAnil Ravindranath return -EACCES; 351589a36810SAnil Ravindranath 351689a36810SAnil Ravindranath /* Populate adapter instance * pointer for use by ioctl */ 351789a36810SAnil Ravindranath pinstance = container_of(inode->i_cdev, struct pmcraid_instance, cdev); 351889a36810SAnil Ravindranath filep->private_data = pinstance; 351989a36810SAnil Ravindranath 352089a36810SAnil Ravindranath return 0; 352189a36810SAnil Ravindranath } 352289a36810SAnil Ravindranath 352389a36810SAnil Ravindranath /** 352489a36810SAnil Ravindranath * pmcraid_fasync - Async notifier registration from applications 352589a36810SAnil Ravindranath * 352689a36810SAnil Ravindranath * This function adds the calling process to a driver global queue. When an 352789a36810SAnil Ravindranath * event occurs, SIGIO will be sent to all processes in this queue. 352889a36810SAnil Ravindranath */ 352989a36810SAnil Ravindranath static int pmcraid_chr_fasync(int fd, struct file *filep, int mode) 353089a36810SAnil Ravindranath { 353189a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 353289a36810SAnil Ravindranath int rc; 353389a36810SAnil Ravindranath 3534660bdddbSCyril Jayaprakash pinstance = filep->private_data; 353589a36810SAnil Ravindranath mutex_lock(&pinstance->aen_queue_lock); 353689a36810SAnil Ravindranath rc = fasync_helper(fd, filep, mode, &pinstance->aen_queue); 353789a36810SAnil Ravindranath mutex_unlock(&pinstance->aen_queue_lock); 353889a36810SAnil Ravindranath 353989a36810SAnil Ravindranath return rc; 354089a36810SAnil Ravindranath } 354189a36810SAnil Ravindranath 354289a36810SAnil Ravindranath 354389a36810SAnil Ravindranath /** 354489a36810SAnil Ravindranath * pmcraid_build_passthrough_ioadls - builds SG elements for passthrough 354589a36810SAnil Ravindranath * commands sent over IOCTL interface 354689a36810SAnil Ravindranath * 354789a36810SAnil Ravindranath * @cmd : pointer to struct pmcraid_cmd 354889a36810SAnil Ravindranath * @buflen : length of the request buffer 354989a36810SAnil Ravindranath * @direction : data transfer direction 355089a36810SAnil Ravindranath * 355189a36810SAnil Ravindranath * Return value 3552af901ca1SAndré Goddard Rosa * 0 on success, non-zero error code on failure 355389a36810SAnil Ravindranath */ 355489a36810SAnil Ravindranath static int pmcraid_build_passthrough_ioadls( 355589a36810SAnil Ravindranath struct pmcraid_cmd *cmd, 355689a36810SAnil Ravindranath int buflen, 355789a36810SAnil Ravindranath int direction 355889a36810SAnil Ravindranath ) 355989a36810SAnil Ravindranath { 356089a36810SAnil Ravindranath struct pmcraid_sglist *sglist = NULL; 356189a36810SAnil Ravindranath struct scatterlist *sg = NULL; 356289a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 356389a36810SAnil Ravindranath struct pmcraid_ioadl_desc *ioadl; 356489a36810SAnil Ravindranath int i; 356589a36810SAnil Ravindranath 356689a36810SAnil Ravindranath sglist = pmcraid_alloc_sglist(buflen); 356789a36810SAnil Ravindranath 356889a36810SAnil Ravindranath if (!sglist) { 356989a36810SAnil Ravindranath pmcraid_err("can't allocate memory for passthrough SGls\n"); 357089a36810SAnil Ravindranath return -ENOMEM; 357189a36810SAnil Ravindranath } 357289a36810SAnil Ravindranath 357389a36810SAnil Ravindranath sglist->num_dma_sg = pci_map_sg(cmd->drv_inst->pdev, 357489a36810SAnil Ravindranath sglist->scatterlist, 357589a36810SAnil Ravindranath sglist->num_sg, direction); 357689a36810SAnil Ravindranath 357789a36810SAnil Ravindranath if (!sglist->num_dma_sg || sglist->num_dma_sg > PMCRAID_MAX_IOADLS) { 357889a36810SAnil Ravindranath dev_err(&cmd->drv_inst->pdev->dev, 357989a36810SAnil Ravindranath "Failed to map passthrough buffer!\n"); 358089a36810SAnil Ravindranath pmcraid_free_sglist(sglist); 358189a36810SAnil Ravindranath return -EIO; 358289a36810SAnil Ravindranath } 358389a36810SAnil Ravindranath 358489a36810SAnil Ravindranath cmd->sglist = sglist; 358589a36810SAnil Ravindranath ioarcb->request_flags0 |= NO_LINK_DESCS; 358689a36810SAnil Ravindranath 358789a36810SAnil Ravindranath ioadl = pmcraid_init_ioadls(cmd, sglist->num_dma_sg); 358889a36810SAnil Ravindranath 358989a36810SAnil Ravindranath /* Initialize IOADL descriptor addresses */ 359089a36810SAnil Ravindranath for_each_sg(sglist->scatterlist, sg, sglist->num_dma_sg, i) { 359189a36810SAnil Ravindranath ioadl[i].data_len = cpu_to_le32(sg_dma_len(sg)); 359289a36810SAnil Ravindranath ioadl[i].address = cpu_to_le64(sg_dma_address(sg)); 359389a36810SAnil Ravindranath ioadl[i].flags = 0; 359489a36810SAnil Ravindranath } 359589a36810SAnil Ravindranath 359689a36810SAnil Ravindranath /* setup the last descriptor */ 359788197966SAnil Ravindranath ioadl[i - 1].flags = IOADL_FLAGS_LAST_DESC; 359889a36810SAnil Ravindranath 359989a36810SAnil Ravindranath return 0; 360089a36810SAnil Ravindranath } 360189a36810SAnil Ravindranath 360289a36810SAnil Ravindranath 360389a36810SAnil Ravindranath /** 360489a36810SAnil Ravindranath * pmcraid_release_passthrough_ioadls - release passthrough ioadls 360589a36810SAnil Ravindranath * 360689a36810SAnil Ravindranath * @cmd: pointer to struct pmcraid_cmd for which ioadls were allocated 360789a36810SAnil Ravindranath * @buflen: size of the request buffer 360889a36810SAnil Ravindranath * @direction: data transfer direction 360989a36810SAnil Ravindranath * 361089a36810SAnil Ravindranath * Return value 3611af901ca1SAndré Goddard Rosa * 0 on success, non-zero error code on failure 361289a36810SAnil Ravindranath */ 361389a36810SAnil Ravindranath static void pmcraid_release_passthrough_ioadls( 361489a36810SAnil Ravindranath struct pmcraid_cmd *cmd, 361589a36810SAnil Ravindranath int buflen, 361689a36810SAnil Ravindranath int direction 361789a36810SAnil Ravindranath ) 361889a36810SAnil Ravindranath { 361989a36810SAnil Ravindranath struct pmcraid_sglist *sglist = cmd->sglist; 362089a36810SAnil Ravindranath 362189a36810SAnil Ravindranath if (buflen > 0) { 362289a36810SAnil Ravindranath pci_unmap_sg(cmd->drv_inst->pdev, 362389a36810SAnil Ravindranath sglist->scatterlist, 362489a36810SAnil Ravindranath sglist->num_sg, 362589a36810SAnil Ravindranath direction); 362689a36810SAnil Ravindranath pmcraid_free_sglist(sglist); 362789a36810SAnil Ravindranath cmd->sglist = NULL; 362889a36810SAnil Ravindranath } 362989a36810SAnil Ravindranath } 363089a36810SAnil Ravindranath 363189a36810SAnil Ravindranath /** 363289a36810SAnil Ravindranath * pmcraid_ioctl_passthrough - handling passthrough IOCTL commands 363389a36810SAnil Ravindranath * 363489a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 363589a36810SAnil Ravindranath * @cmd: ioctl code 363689a36810SAnil Ravindranath * @arg: pointer to pmcraid_passthrough_buffer user buffer 363789a36810SAnil Ravindranath * 363889a36810SAnil Ravindranath * Return value 3639af901ca1SAndré Goddard Rosa * 0 on success, non-zero error code on failure 364089a36810SAnil Ravindranath */ 364189a36810SAnil Ravindranath static long pmcraid_ioctl_passthrough( 364289a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 364389a36810SAnil Ravindranath unsigned int ioctl_cmd, 364489a36810SAnil Ravindranath unsigned int buflen, 36453397623bSArnd Bergmann void __user *arg 364689a36810SAnil Ravindranath ) 364789a36810SAnil Ravindranath { 364889a36810SAnil Ravindranath struct pmcraid_passthrough_ioctl_buffer *buffer; 364989a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb; 365089a36810SAnil Ravindranath struct pmcraid_cmd *cmd; 365189a36810SAnil Ravindranath struct pmcraid_cmd *cancel_cmd; 36523397623bSArnd Bergmann void __user *request_buffer; 365389a36810SAnil Ravindranath unsigned long request_offset; 365489a36810SAnil Ravindranath unsigned long lock_flags; 36553397623bSArnd Bergmann void __user *ioasa; 3656c20c4267SAnil Ravindranath u32 ioasc; 365789a36810SAnil Ravindranath int request_size; 365889a36810SAnil Ravindranath int buffer_size; 365989a36810SAnil Ravindranath u8 access, direction; 366089a36810SAnil Ravindranath int rc = 0; 366189a36810SAnil Ravindranath 366289a36810SAnil Ravindranath /* If IOA reset is in progress, wait 10 secs for reset to complete */ 366389a36810SAnil Ravindranath if (pinstance->ioa_reset_in_progress) { 366489a36810SAnil Ravindranath rc = wait_event_interruptible_timeout( 366589a36810SAnil Ravindranath pinstance->reset_wait_q, 366689a36810SAnil Ravindranath !pinstance->ioa_reset_in_progress, 366789a36810SAnil Ravindranath msecs_to_jiffies(10000)); 366889a36810SAnil Ravindranath 366989a36810SAnil Ravindranath if (!rc) 367089a36810SAnil Ravindranath return -ETIMEDOUT; 367189a36810SAnil Ravindranath else if (rc < 0) 367289a36810SAnil Ravindranath return -ERESTARTSYS; 367389a36810SAnil Ravindranath } 367489a36810SAnil Ravindranath 367589a36810SAnil Ravindranath /* If adapter is not in operational state, return error */ 367689a36810SAnil Ravindranath if (pinstance->ioa_state != IOA_STATE_OPERATIONAL) { 367789a36810SAnil Ravindranath pmcraid_err("IOA is not operational\n"); 367889a36810SAnil Ravindranath return -ENOTTY; 367989a36810SAnil Ravindranath } 368089a36810SAnil Ravindranath 368189a36810SAnil Ravindranath buffer_size = sizeof(struct pmcraid_passthrough_ioctl_buffer); 368289a36810SAnil Ravindranath buffer = kmalloc(buffer_size, GFP_KERNEL); 368389a36810SAnil Ravindranath 368489a36810SAnil Ravindranath if (!buffer) { 368589a36810SAnil Ravindranath pmcraid_err("no memory for passthrough buffer\n"); 368689a36810SAnil Ravindranath return -ENOMEM; 368789a36810SAnil Ravindranath } 368889a36810SAnil Ravindranath 368989a36810SAnil Ravindranath request_offset = 369089a36810SAnil Ravindranath offsetof(struct pmcraid_passthrough_ioctl_buffer, request_buffer); 369189a36810SAnil Ravindranath 369289a36810SAnil Ravindranath request_buffer = arg + request_offset; 369389a36810SAnil Ravindranath 36943397623bSArnd Bergmann rc = __copy_from_user(buffer, arg, 369589a36810SAnil Ravindranath sizeof(struct pmcraid_passthrough_ioctl_buffer)); 3696592488a3SAnil Ravindranath 36973397623bSArnd Bergmann ioasa = arg + offsetof(struct pmcraid_passthrough_ioctl_buffer, ioasa); 3698592488a3SAnil Ravindranath 369989a36810SAnil Ravindranath if (rc) { 370089a36810SAnil Ravindranath pmcraid_err("ioctl: can't copy passthrough buffer\n"); 370189a36810SAnil Ravindranath rc = -EFAULT; 370289a36810SAnil Ravindranath goto out_free_buffer; 370389a36810SAnil Ravindranath } 370489a36810SAnil Ravindranath 370545c80be6SArnd Bergmann request_size = le32_to_cpu(buffer->ioarcb.data_transfer_length); 370689a36810SAnil Ravindranath 370789a36810SAnil Ravindranath if (buffer->ioarcb.request_flags0 & TRANSFER_DIR_WRITE) { 370889a36810SAnil Ravindranath access = VERIFY_READ; 370989a36810SAnil Ravindranath direction = DMA_TO_DEVICE; 371089a36810SAnil Ravindranath } else { 371189a36810SAnil Ravindranath access = VERIFY_WRITE; 371289a36810SAnil Ravindranath direction = DMA_FROM_DEVICE; 371389a36810SAnil Ravindranath } 371489a36810SAnil Ravindranath 371589a36810SAnil Ravindranath if (request_size > 0) { 371689a36810SAnil Ravindranath rc = access_ok(access, arg, request_offset + request_size); 371789a36810SAnil Ravindranath 371889a36810SAnil Ravindranath if (!rc) { 371989a36810SAnil Ravindranath rc = -EFAULT; 372089a36810SAnil Ravindranath goto out_free_buffer; 372189a36810SAnil Ravindranath } 37225f6279daSDan Rosenberg } else if (request_size < 0) { 37235f6279daSDan Rosenberg rc = -EINVAL; 37245f6279daSDan Rosenberg goto out_free_buffer; 372589a36810SAnil Ravindranath } 372689a36810SAnil Ravindranath 372789a36810SAnil Ravindranath /* check if we have any additional command parameters */ 372845c80be6SArnd Bergmann if (le16_to_cpu(buffer->ioarcb.add_cmd_param_length) 372945c80be6SArnd Bergmann > PMCRAID_ADD_CMD_PARAM_LEN) { 373089a36810SAnil Ravindranath rc = -EINVAL; 373189a36810SAnil Ravindranath goto out_free_buffer; 373289a36810SAnil Ravindranath } 373389a36810SAnil Ravindranath 373489a36810SAnil Ravindranath cmd = pmcraid_get_free_cmd(pinstance); 373589a36810SAnil Ravindranath 373689a36810SAnil Ravindranath if (!cmd) { 373789a36810SAnil Ravindranath pmcraid_err("free command block is not available\n"); 373889a36810SAnil Ravindranath rc = -ENOMEM; 373989a36810SAnil Ravindranath goto out_free_buffer; 374089a36810SAnil Ravindranath } 374189a36810SAnil Ravindranath 374289a36810SAnil Ravindranath cmd->scsi_cmd = NULL; 374389a36810SAnil Ravindranath ioarcb = &(cmd->ioa_cb->ioarcb); 374489a36810SAnil Ravindranath 374589a36810SAnil Ravindranath /* Copy the user-provided IOARCB stuff field by field */ 374689a36810SAnil Ravindranath ioarcb->resource_handle = buffer->ioarcb.resource_handle; 374789a36810SAnil Ravindranath ioarcb->data_transfer_length = buffer->ioarcb.data_transfer_length; 374889a36810SAnil Ravindranath ioarcb->cmd_timeout = buffer->ioarcb.cmd_timeout; 374989a36810SAnil Ravindranath ioarcb->request_type = buffer->ioarcb.request_type; 375089a36810SAnil Ravindranath ioarcb->request_flags0 = buffer->ioarcb.request_flags0; 375189a36810SAnil Ravindranath ioarcb->request_flags1 = buffer->ioarcb.request_flags1; 375289a36810SAnil Ravindranath memcpy(ioarcb->cdb, buffer->ioarcb.cdb, PMCRAID_MAX_CDB_LEN); 375389a36810SAnil Ravindranath 375489a36810SAnil Ravindranath if (buffer->ioarcb.add_cmd_param_length) { 375589a36810SAnil Ravindranath ioarcb->add_cmd_param_length = 375689a36810SAnil Ravindranath buffer->ioarcb.add_cmd_param_length; 375789a36810SAnil Ravindranath ioarcb->add_cmd_param_offset = 375889a36810SAnil Ravindranath buffer->ioarcb.add_cmd_param_offset; 375989a36810SAnil Ravindranath memcpy(ioarcb->add_data.u.add_cmd_params, 376089a36810SAnil Ravindranath buffer->ioarcb.add_data.u.add_cmd_params, 376145c80be6SArnd Bergmann le16_to_cpu(buffer->ioarcb.add_cmd_param_length)); 376289a36810SAnil Ravindranath } 376389a36810SAnil Ravindranath 3764c20c4267SAnil Ravindranath /* set hrrq number where the IOA should respond to. Note that all cmds 3765c20c4267SAnil Ravindranath * generated internally uses hrrq_id 0, exception to this is the cmd 3766c20c4267SAnil Ravindranath * block of scsi_cmd which is re-used (e.g. cancel/abort), which uses 3767c20c4267SAnil Ravindranath * hrrq_id assigned here in queuecommand 3768c20c4267SAnil Ravindranath */ 3769c20c4267SAnil Ravindranath ioarcb->hrrq_id = atomic_add_return(1, &(pinstance->last_message_id)) % 3770c20c4267SAnil Ravindranath pinstance->num_hrrq; 3771c20c4267SAnil Ravindranath 377289a36810SAnil Ravindranath if (request_size) { 377389a36810SAnil Ravindranath rc = pmcraid_build_passthrough_ioadls(cmd, 377489a36810SAnil Ravindranath request_size, 377589a36810SAnil Ravindranath direction); 377689a36810SAnil Ravindranath if (rc) { 377789a36810SAnil Ravindranath pmcraid_err("couldn't build passthrough ioadls\n"); 37782d76a247SQuentin Lambert goto out_free_cmd; 377989a36810SAnil Ravindranath } 3780b5b51544SDan Rosenberg } else if (request_size < 0) { 3781b5b51544SDan Rosenberg rc = -EINVAL; 37822d76a247SQuentin Lambert goto out_free_cmd; 378389a36810SAnil Ravindranath } 378489a36810SAnil Ravindranath 378589a36810SAnil Ravindranath /* If data is being written into the device, copy the data from user 378689a36810SAnil Ravindranath * buffers 378789a36810SAnil Ravindranath */ 378889a36810SAnil Ravindranath if (direction == DMA_TO_DEVICE && request_size > 0) { 378989a36810SAnil Ravindranath rc = pmcraid_copy_sglist(cmd->sglist, 379089a36810SAnil Ravindranath request_buffer, 379189a36810SAnil Ravindranath request_size, 379289a36810SAnil Ravindranath direction); 379389a36810SAnil Ravindranath if (rc) { 379489a36810SAnil Ravindranath pmcraid_err("failed to copy user buffer\n"); 379589a36810SAnil Ravindranath goto out_free_sglist; 379689a36810SAnil Ravindranath } 379789a36810SAnil Ravindranath } 379889a36810SAnil Ravindranath 379989a36810SAnil Ravindranath /* passthrough ioctl is a blocking command so, put the user to sleep 380089a36810SAnil Ravindranath * until timeout. Note that a timeout value of 0 means, do timeout. 380189a36810SAnil Ravindranath */ 380289a36810SAnil Ravindranath cmd->cmd_done = pmcraid_internal_done; 380389a36810SAnil Ravindranath init_completion(&cmd->wait_for_completion); 380489a36810SAnil Ravindranath cmd->completion_req = 1; 380589a36810SAnil Ravindranath 380689a36810SAnil Ravindranath pmcraid_info("command(%d) (CDB[0] = %x) for %x\n", 380789a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle) >> 2, 380889a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 380989a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioarcb.resource_handle)); 381089a36810SAnil Ravindranath 381189a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 381289a36810SAnil Ravindranath _pmcraid_fire_command(cmd); 381389a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 381489a36810SAnil Ravindranath 3815c20c4267SAnil Ravindranath /* NOTE ! Remove the below line once abort_task is implemented 3816c20c4267SAnil Ravindranath * in firmware. This line disables ioctl command timeout handling logic 3817c20c4267SAnil Ravindranath * similar to IO command timeout handling, making ioctl commands to wait 3818c20c4267SAnil Ravindranath * until the command completion regardless of timeout value specified in 3819c20c4267SAnil Ravindranath * ioarcb 3820c20c4267SAnil Ravindranath */ 3821c20c4267SAnil Ravindranath buffer->ioarcb.cmd_timeout = 0; 3822c20c4267SAnil Ravindranath 382389a36810SAnil Ravindranath /* If command timeout is specified put caller to wait till that time, 382489a36810SAnil Ravindranath * otherwise it would be blocking wait. If command gets timed out, it 382589a36810SAnil Ravindranath * will be aborted. 382689a36810SAnil Ravindranath */ 382789a36810SAnil Ravindranath if (buffer->ioarcb.cmd_timeout == 0) { 382889a36810SAnil Ravindranath wait_for_completion(&cmd->wait_for_completion); 382989a36810SAnil Ravindranath } else if (!wait_for_completion_timeout( 383089a36810SAnil Ravindranath &cmd->wait_for_completion, 383145c80be6SArnd Bergmann msecs_to_jiffies(le16_to_cpu(buffer->ioarcb.cmd_timeout) * 1000))) { 383289a36810SAnil Ravindranath 383389a36810SAnil Ravindranath pmcraid_info("aborting cmd %d (CDB[0] = %x) due to timeout\n", 383445c80be6SArnd Bergmann le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle) >> 2, 383589a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0]); 383689a36810SAnil Ravindranath 383789a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 383889a36810SAnil Ravindranath cancel_cmd = pmcraid_abort_cmd(cmd); 383989a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 384089a36810SAnil Ravindranath 384189a36810SAnil Ravindranath if (cancel_cmd) { 384289a36810SAnil Ravindranath wait_for_completion(&cancel_cmd->wait_for_completion); 384345c80be6SArnd Bergmann ioasc = le32_to_cpu(cancel_cmd->ioa_cb->ioasa.ioasc); 384489a36810SAnil Ravindranath pmcraid_return_cmd(cancel_cmd); 3845c20c4267SAnil Ravindranath 3846c20c4267SAnil Ravindranath /* if abort task couldn't find the command i.e it got 3847c20c4267SAnil Ravindranath * completed prior to aborting, return good completion. 384825985edcSLucas De Marchi * if command got aborted successfully or there was IOA 3849c20c4267SAnil Ravindranath * reset due to abort task itself getting timedout then 3850c20c4267SAnil Ravindranath * return -ETIMEDOUT 3851c20c4267SAnil Ravindranath */ 3852c20c4267SAnil Ravindranath if (ioasc == PMCRAID_IOASC_IOA_WAS_RESET || 3853c20c4267SAnil Ravindranath PMCRAID_IOASC_SENSE_KEY(ioasc) == 0x00) { 3854c20c4267SAnil Ravindranath if (ioasc != PMCRAID_IOASC_GC_IOARCB_NOTFOUND) 3855c20c4267SAnil Ravindranath rc = -ETIMEDOUT; 3856c20c4267SAnil Ravindranath goto out_handle_response; 3857c20c4267SAnil Ravindranath } 385889a36810SAnil Ravindranath } 385989a36810SAnil Ravindranath 3860c20c4267SAnil Ravindranath /* no command block for abort task or abort task failed to abort 3861c20c4267SAnil Ravindranath * the IOARCB, then wait for 150 more seconds and initiate reset 3862c20c4267SAnil Ravindranath * sequence after timeout 3863c20c4267SAnil Ravindranath */ 3864c20c4267SAnil Ravindranath if (!wait_for_completion_timeout( 3865c20c4267SAnil Ravindranath &cmd->wait_for_completion, 3866c20c4267SAnil Ravindranath msecs_to_jiffies(150 * 1000))) { 3867c20c4267SAnil Ravindranath pmcraid_reset_bringup(cmd->drv_inst); 3868c20c4267SAnil Ravindranath rc = -ETIMEDOUT; 3869c20c4267SAnil Ravindranath } 387089a36810SAnil Ravindranath } 387189a36810SAnil Ravindranath 3872c20c4267SAnil Ravindranath out_handle_response: 3873592488a3SAnil Ravindranath /* copy entire IOASA buffer and return IOCTL success. 3874592488a3SAnil Ravindranath * If copying IOASA to user-buffer fails, return 387589a36810SAnil Ravindranath * EFAULT 387689a36810SAnil Ravindranath */ 387789a36810SAnil Ravindranath if (copy_to_user(ioasa, &cmd->ioa_cb->ioasa, 387889a36810SAnil Ravindranath sizeof(struct pmcraid_ioasa))) { 387989a36810SAnil Ravindranath pmcraid_err("failed to copy ioasa buffer to user\n"); 388089a36810SAnil Ravindranath rc = -EFAULT; 388189a36810SAnil Ravindranath } 3882c20c4267SAnil Ravindranath 388389a36810SAnil Ravindranath /* If the data transfer was from device, copy the data onto user 388489a36810SAnil Ravindranath * buffers 388589a36810SAnil Ravindranath */ 388689a36810SAnil Ravindranath else if (direction == DMA_FROM_DEVICE && request_size > 0) { 388789a36810SAnil Ravindranath rc = pmcraid_copy_sglist(cmd->sglist, 388889a36810SAnil Ravindranath request_buffer, 388989a36810SAnil Ravindranath request_size, 389089a36810SAnil Ravindranath direction); 389189a36810SAnil Ravindranath if (rc) { 389289a36810SAnil Ravindranath pmcraid_err("failed to copy user buffer\n"); 389389a36810SAnil Ravindranath rc = -EFAULT; 389489a36810SAnil Ravindranath } 389589a36810SAnil Ravindranath } 389689a36810SAnil Ravindranath 389789a36810SAnil Ravindranath out_free_sglist: 389889a36810SAnil Ravindranath pmcraid_release_passthrough_ioadls(cmd, request_size, direction); 38992d76a247SQuentin Lambert 39002d76a247SQuentin Lambert out_free_cmd: 390189a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 390289a36810SAnil Ravindranath 390389a36810SAnil Ravindranath out_free_buffer: 390489a36810SAnil Ravindranath kfree(buffer); 390589a36810SAnil Ravindranath 390689a36810SAnil Ravindranath return rc; 390789a36810SAnil Ravindranath } 390889a36810SAnil Ravindranath 390989a36810SAnil Ravindranath 391089a36810SAnil Ravindranath 391189a36810SAnil Ravindranath 391289a36810SAnil Ravindranath /** 391389a36810SAnil Ravindranath * pmcraid_ioctl_driver - ioctl handler for commands handled by driver itself 391489a36810SAnil Ravindranath * 391589a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 391689a36810SAnil Ravindranath * @cmd: ioctl command passed in 391789a36810SAnil Ravindranath * @buflen: length of user_buffer 391889a36810SAnil Ravindranath * @user_buffer: user buffer pointer 391989a36810SAnil Ravindranath * 392089a36810SAnil Ravindranath * Return Value 392189a36810SAnil Ravindranath * 0 in case of success, otherwise appropriate error code 392289a36810SAnil Ravindranath */ 392389a36810SAnil Ravindranath static long pmcraid_ioctl_driver( 392489a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 392589a36810SAnil Ravindranath unsigned int cmd, 392689a36810SAnil Ravindranath unsigned int buflen, 392789a36810SAnil Ravindranath void __user *user_buffer 392889a36810SAnil Ravindranath ) 392989a36810SAnil Ravindranath { 393089a36810SAnil Ravindranath int rc = -ENOSYS; 393189a36810SAnil Ravindranath 393289a36810SAnil Ravindranath if (!access_ok(VERIFY_READ, user_buffer, _IOC_SIZE(cmd))) { 393389a36810SAnil Ravindranath pmcraid_err("ioctl_driver: access fault in request buffer\n"); 393489a36810SAnil Ravindranath return -EFAULT; 393589a36810SAnil Ravindranath } 393689a36810SAnil Ravindranath 393789a36810SAnil Ravindranath switch (cmd) { 393889a36810SAnil Ravindranath case PMCRAID_IOCTL_RESET_ADAPTER: 393989a36810SAnil Ravindranath pmcraid_reset_bringup(pinstance); 394089a36810SAnil Ravindranath rc = 0; 394189a36810SAnil Ravindranath break; 394289a36810SAnil Ravindranath 394389a36810SAnil Ravindranath default: 394489a36810SAnil Ravindranath break; 394589a36810SAnil Ravindranath } 394689a36810SAnil Ravindranath 394789a36810SAnil Ravindranath return rc; 394889a36810SAnil Ravindranath } 394989a36810SAnil Ravindranath 395089a36810SAnil Ravindranath /** 395189a36810SAnil Ravindranath * pmcraid_check_ioctl_buffer - check for proper access to user buffer 395289a36810SAnil Ravindranath * 395389a36810SAnil Ravindranath * @cmd: ioctl command 395489a36810SAnil Ravindranath * @arg: user buffer 395589a36810SAnil Ravindranath * @hdr: pointer to kernel memory for pmcraid_ioctl_header 395689a36810SAnil Ravindranath * 395789a36810SAnil Ravindranath * Return Value 395889a36810SAnil Ravindranath * negetive error code if there are access issues, otherwise zero. 395989a36810SAnil Ravindranath * Upon success, returns ioctl header copied out of user buffer. 396089a36810SAnil Ravindranath */ 396189a36810SAnil Ravindranath 396289a36810SAnil Ravindranath static int pmcraid_check_ioctl_buffer( 396389a36810SAnil Ravindranath int cmd, 396489a36810SAnil Ravindranath void __user *arg, 396589a36810SAnil Ravindranath struct pmcraid_ioctl_header *hdr 396689a36810SAnil Ravindranath ) 396789a36810SAnil Ravindranath { 396889a36810SAnil Ravindranath int rc = 0; 396989a36810SAnil Ravindranath int access = VERIFY_READ; 397089a36810SAnil Ravindranath 397189a36810SAnil Ravindranath if (copy_from_user(hdr, arg, sizeof(struct pmcraid_ioctl_header))) { 397289a36810SAnil Ravindranath pmcraid_err("couldn't copy ioctl header from user buffer\n"); 397389a36810SAnil Ravindranath return -EFAULT; 397489a36810SAnil Ravindranath } 397589a36810SAnil Ravindranath 397689a36810SAnil Ravindranath /* check for valid driver signature */ 397789a36810SAnil Ravindranath rc = memcmp(hdr->signature, 397889a36810SAnil Ravindranath PMCRAID_IOCTL_SIGNATURE, 397989a36810SAnil Ravindranath sizeof(hdr->signature)); 398089a36810SAnil Ravindranath if (rc) { 398189a36810SAnil Ravindranath pmcraid_err("signature verification failed\n"); 398289a36810SAnil Ravindranath return -EINVAL; 398389a36810SAnil Ravindranath } 398489a36810SAnil Ravindranath 398589a36810SAnil Ravindranath /* check for appropriate buffer access */ 398689a36810SAnil Ravindranath if ((_IOC_DIR(cmd) & _IOC_READ) == _IOC_READ) 398789a36810SAnil Ravindranath access = VERIFY_WRITE; 398889a36810SAnil Ravindranath 398989a36810SAnil Ravindranath rc = access_ok(access, 399089a36810SAnil Ravindranath (arg + sizeof(struct pmcraid_ioctl_header)), 399189a36810SAnil Ravindranath hdr->buffer_length); 399289a36810SAnil Ravindranath if (!rc) { 399389a36810SAnil Ravindranath pmcraid_err("access failed for user buffer of size %d\n", 399489a36810SAnil Ravindranath hdr->buffer_length); 399589a36810SAnil Ravindranath return -EFAULT; 399689a36810SAnil Ravindranath } 399789a36810SAnil Ravindranath 399889a36810SAnil Ravindranath return 0; 399989a36810SAnil Ravindranath } 400089a36810SAnil Ravindranath 400189a36810SAnil Ravindranath /** 400289a36810SAnil Ravindranath * pmcraid_ioctl - char node ioctl entry point 400389a36810SAnil Ravindranath */ 400489a36810SAnil Ravindranath static long pmcraid_chr_ioctl( 400589a36810SAnil Ravindranath struct file *filep, 400689a36810SAnil Ravindranath unsigned int cmd, 400789a36810SAnil Ravindranath unsigned long arg 400889a36810SAnil Ravindranath ) 400989a36810SAnil Ravindranath { 401089a36810SAnil Ravindranath struct pmcraid_instance *pinstance = NULL; 401189a36810SAnil Ravindranath struct pmcraid_ioctl_header *hdr = NULL; 40123397623bSArnd Bergmann void __user *argp = (void __user *)arg; 401389a36810SAnil Ravindranath int retval = -ENOTTY; 401489a36810SAnil Ravindranath 4015a63ec376SDave Jones hdr = kmalloc(sizeof(struct pmcraid_ioctl_header), GFP_KERNEL); 401689a36810SAnil Ravindranath 401789a36810SAnil Ravindranath if (!hdr) { 40184f91b114SJesper Juhl pmcraid_err("failed to allocate memory for ioctl header\n"); 401989a36810SAnil Ravindranath return -ENOMEM; 402089a36810SAnil Ravindranath } 402189a36810SAnil Ravindranath 40223397623bSArnd Bergmann retval = pmcraid_check_ioctl_buffer(cmd, argp, hdr); 402389a36810SAnil Ravindranath 402489a36810SAnil Ravindranath if (retval) { 402589a36810SAnil Ravindranath pmcraid_info("chr_ioctl: header check failed\n"); 402689a36810SAnil Ravindranath kfree(hdr); 402789a36810SAnil Ravindranath return retval; 402889a36810SAnil Ravindranath } 402989a36810SAnil Ravindranath 4030660bdddbSCyril Jayaprakash pinstance = filep->private_data; 403189a36810SAnil Ravindranath 403289a36810SAnil Ravindranath if (!pinstance) { 403389a36810SAnil Ravindranath pmcraid_info("adapter instance is not found\n"); 403489a36810SAnil Ravindranath kfree(hdr); 403589a36810SAnil Ravindranath return -ENOTTY; 403689a36810SAnil Ravindranath } 403789a36810SAnil Ravindranath 403889a36810SAnil Ravindranath switch (_IOC_TYPE(cmd)) { 403989a36810SAnil Ravindranath 404089a36810SAnil Ravindranath case PMCRAID_PASSTHROUGH_IOCTL: 404189a36810SAnil Ravindranath /* If ioctl code is to download microcode, we need to block 404289a36810SAnil Ravindranath * mid-layer requests. 404389a36810SAnil Ravindranath */ 404489a36810SAnil Ravindranath if (cmd == PMCRAID_IOCTL_DOWNLOAD_MICROCODE) 404589a36810SAnil Ravindranath scsi_block_requests(pinstance->host); 404689a36810SAnil Ravindranath 40473397623bSArnd Bergmann retval = pmcraid_ioctl_passthrough(pinstance, cmd, 40483397623bSArnd Bergmann hdr->buffer_length, argp); 404989a36810SAnil Ravindranath 405089a36810SAnil Ravindranath if (cmd == PMCRAID_IOCTL_DOWNLOAD_MICROCODE) 405189a36810SAnil Ravindranath scsi_unblock_requests(pinstance->host); 405289a36810SAnil Ravindranath break; 405389a36810SAnil Ravindranath 405489a36810SAnil Ravindranath case PMCRAID_DRIVER_IOCTL: 405589a36810SAnil Ravindranath arg += sizeof(struct pmcraid_ioctl_header); 40563397623bSArnd Bergmann retval = pmcraid_ioctl_driver(pinstance, cmd, 40573397623bSArnd Bergmann hdr->buffer_length, argp); 405889a36810SAnil Ravindranath break; 405989a36810SAnil Ravindranath 406089a36810SAnil Ravindranath default: 406189a36810SAnil Ravindranath retval = -ENOTTY; 406289a36810SAnil Ravindranath break; 406389a36810SAnil Ravindranath } 406489a36810SAnil Ravindranath 406589a36810SAnil Ravindranath kfree(hdr); 406689a36810SAnil Ravindranath 406789a36810SAnil Ravindranath return retval; 406889a36810SAnil Ravindranath } 406989a36810SAnil Ravindranath 407089a36810SAnil Ravindranath /** 407189a36810SAnil Ravindranath * File operations structure for management interface 407289a36810SAnil Ravindranath */ 407389a36810SAnil Ravindranath static const struct file_operations pmcraid_fops = { 407489a36810SAnil Ravindranath .owner = THIS_MODULE, 407589a36810SAnil Ravindranath .open = pmcraid_chr_open, 407689a36810SAnil Ravindranath .fasync = pmcraid_chr_fasync, 407789a36810SAnil Ravindranath .unlocked_ioctl = pmcraid_chr_ioctl, 407889a36810SAnil Ravindranath #ifdef CONFIG_COMPAT 407989a36810SAnil Ravindranath .compat_ioctl = pmcraid_chr_ioctl, 408089a36810SAnil Ravindranath #endif 40816038f373SArnd Bergmann .llseek = noop_llseek, 408289a36810SAnil Ravindranath }; 408389a36810SAnil Ravindranath 408489a36810SAnil Ravindranath 408589a36810SAnil Ravindranath 408689a36810SAnil Ravindranath 408789a36810SAnil Ravindranath /** 408889a36810SAnil Ravindranath * pmcraid_show_log_level - Display adapter's error logging level 408989a36810SAnil Ravindranath * @dev: class device struct 409089a36810SAnil Ravindranath * @buf: buffer 409189a36810SAnil Ravindranath * 409289a36810SAnil Ravindranath * Return value: 409389a36810SAnil Ravindranath * number of bytes printed to buffer 409489a36810SAnil Ravindranath */ 409589a36810SAnil Ravindranath static ssize_t pmcraid_show_log_level( 409689a36810SAnil Ravindranath struct device *dev, 409789a36810SAnil Ravindranath struct device_attribute *attr, 409889a36810SAnil Ravindranath char *buf) 409989a36810SAnil Ravindranath { 410089a36810SAnil Ravindranath struct Scsi_Host *shost = class_to_shost(dev); 410189a36810SAnil Ravindranath struct pmcraid_instance *pinstance = 410289a36810SAnil Ravindranath (struct pmcraid_instance *)shost->hostdata; 410389a36810SAnil Ravindranath return snprintf(buf, PAGE_SIZE, "%d\n", pinstance->current_log_level); 410489a36810SAnil Ravindranath } 410589a36810SAnil Ravindranath 410689a36810SAnil Ravindranath /** 410789a36810SAnil Ravindranath * pmcraid_store_log_level - Change the adapter's error logging level 410889a36810SAnil Ravindranath * @dev: class device struct 410989a36810SAnil Ravindranath * @buf: buffer 411089a36810SAnil Ravindranath * @count: not used 411189a36810SAnil Ravindranath * 411289a36810SAnil Ravindranath * Return value: 411389a36810SAnil Ravindranath * number of bytes printed to buffer 411489a36810SAnil Ravindranath */ 411589a36810SAnil Ravindranath static ssize_t pmcraid_store_log_level( 411689a36810SAnil Ravindranath struct device *dev, 411789a36810SAnil Ravindranath struct device_attribute *attr, 411889a36810SAnil Ravindranath const char *buf, 411989a36810SAnil Ravindranath size_t count 412089a36810SAnil Ravindranath ) 412189a36810SAnil Ravindranath { 412289a36810SAnil Ravindranath struct Scsi_Host *shost; 412389a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 4124f7c65af5SDaniel Walter u8 val; 412589a36810SAnil Ravindranath 4126f7c65af5SDaniel Walter if (kstrtou8(buf, 10, &val)) 412789a36810SAnil Ravindranath return -EINVAL; 412889a36810SAnil Ravindranath /* log-level should be from 0 to 2 */ 412989a36810SAnil Ravindranath if (val > 2) 413089a36810SAnil Ravindranath return -EINVAL; 413189a36810SAnil Ravindranath 413289a36810SAnil Ravindranath shost = class_to_shost(dev); 413389a36810SAnil Ravindranath pinstance = (struct pmcraid_instance *)shost->hostdata; 413489a36810SAnil Ravindranath pinstance->current_log_level = val; 413589a36810SAnil Ravindranath 413689a36810SAnil Ravindranath return strlen(buf); 413789a36810SAnil Ravindranath } 413889a36810SAnil Ravindranath 413989a36810SAnil Ravindranath static struct device_attribute pmcraid_log_level_attr = { 414089a36810SAnil Ravindranath .attr = { 414189a36810SAnil Ravindranath .name = "log_level", 414289a36810SAnil Ravindranath .mode = S_IRUGO | S_IWUSR, 414389a36810SAnil Ravindranath }, 414489a36810SAnil Ravindranath .show = pmcraid_show_log_level, 414589a36810SAnil Ravindranath .store = pmcraid_store_log_level, 414689a36810SAnil Ravindranath }; 414789a36810SAnil Ravindranath 414889a36810SAnil Ravindranath /** 414989a36810SAnil Ravindranath * pmcraid_show_drv_version - Display driver version 415089a36810SAnil Ravindranath * @dev: class device struct 415189a36810SAnil Ravindranath * @buf: buffer 415289a36810SAnil Ravindranath * 415389a36810SAnil Ravindranath * Return value: 415489a36810SAnil Ravindranath * number of bytes printed to buffer 415589a36810SAnil Ravindranath */ 415689a36810SAnil Ravindranath static ssize_t pmcraid_show_drv_version( 415789a36810SAnil Ravindranath struct device *dev, 415889a36810SAnil Ravindranath struct device_attribute *attr, 415989a36810SAnil Ravindranath char *buf 416089a36810SAnil Ravindranath ) 416189a36810SAnil Ravindranath { 4162a1b66665SMichal Marek return snprintf(buf, PAGE_SIZE, "version: %s\n", 4163a1b66665SMichal Marek PMCRAID_DRIVER_VERSION); 416489a36810SAnil Ravindranath } 416589a36810SAnil Ravindranath 416689a36810SAnil Ravindranath static struct device_attribute pmcraid_driver_version_attr = { 416789a36810SAnil Ravindranath .attr = { 416889a36810SAnil Ravindranath .name = "drv_version", 416989a36810SAnil Ravindranath .mode = S_IRUGO, 417089a36810SAnil Ravindranath }, 417189a36810SAnil Ravindranath .show = pmcraid_show_drv_version, 417289a36810SAnil Ravindranath }; 417389a36810SAnil Ravindranath 417489a36810SAnil Ravindranath /** 417589a36810SAnil Ravindranath * pmcraid_show_io_adapter_id - Display driver assigned adapter id 417689a36810SAnil Ravindranath * @dev: class device struct 417789a36810SAnil Ravindranath * @buf: buffer 417889a36810SAnil Ravindranath * 417989a36810SAnil Ravindranath * Return value: 418089a36810SAnil Ravindranath * number of bytes printed to buffer 418189a36810SAnil Ravindranath */ 418289a36810SAnil Ravindranath static ssize_t pmcraid_show_adapter_id( 418389a36810SAnil Ravindranath struct device *dev, 418489a36810SAnil Ravindranath struct device_attribute *attr, 418589a36810SAnil Ravindranath char *buf 418689a36810SAnil Ravindranath ) 418789a36810SAnil Ravindranath { 418889a36810SAnil Ravindranath struct Scsi_Host *shost = class_to_shost(dev); 418989a36810SAnil Ravindranath struct pmcraid_instance *pinstance = 419089a36810SAnil Ravindranath (struct pmcraid_instance *)shost->hostdata; 419189a36810SAnil Ravindranath u32 adapter_id = (pinstance->pdev->bus->number << 8) | 419289a36810SAnil Ravindranath pinstance->pdev->devfn; 419389a36810SAnil Ravindranath u32 aen_group = pmcraid_event_family.id; 419489a36810SAnil Ravindranath 419589a36810SAnil Ravindranath return snprintf(buf, PAGE_SIZE, 419689a36810SAnil Ravindranath "adapter id: %d\nminor: %d\naen group: %d\n", 419789a36810SAnil Ravindranath adapter_id, MINOR(pinstance->cdev.dev), aen_group); 419889a36810SAnil Ravindranath } 419989a36810SAnil Ravindranath 420089a36810SAnil Ravindranath static struct device_attribute pmcraid_adapter_id_attr = { 420189a36810SAnil Ravindranath .attr = { 420289a36810SAnil Ravindranath .name = "adapter_id", 42035a0ccb6bSAlan .mode = S_IRUGO, 420489a36810SAnil Ravindranath }, 420589a36810SAnil Ravindranath .show = pmcraid_show_adapter_id, 420689a36810SAnil Ravindranath }; 420789a36810SAnil Ravindranath 420889a36810SAnil Ravindranath static struct device_attribute *pmcraid_host_attrs[] = { 420989a36810SAnil Ravindranath &pmcraid_log_level_attr, 421089a36810SAnil Ravindranath &pmcraid_driver_version_attr, 421189a36810SAnil Ravindranath &pmcraid_adapter_id_attr, 421289a36810SAnil Ravindranath NULL, 421389a36810SAnil Ravindranath }; 421489a36810SAnil Ravindranath 421589a36810SAnil Ravindranath 421689a36810SAnil Ravindranath /* host template structure for pmcraid driver */ 421789a36810SAnil Ravindranath static struct scsi_host_template pmcraid_host_template = { 421889a36810SAnil Ravindranath .module = THIS_MODULE, 421989a36810SAnil Ravindranath .name = PMCRAID_DRIVER_NAME, 422089a36810SAnil Ravindranath .queuecommand = pmcraid_queuecommand, 422189a36810SAnil Ravindranath .eh_abort_handler = pmcraid_eh_abort_handler, 422289a36810SAnil Ravindranath .eh_bus_reset_handler = pmcraid_eh_bus_reset_handler, 422389a36810SAnil Ravindranath .eh_target_reset_handler = pmcraid_eh_target_reset_handler, 422489a36810SAnil Ravindranath .eh_device_reset_handler = pmcraid_eh_device_reset_handler, 422589a36810SAnil Ravindranath .eh_host_reset_handler = pmcraid_eh_host_reset_handler, 422689a36810SAnil Ravindranath 422789a36810SAnil Ravindranath .slave_alloc = pmcraid_slave_alloc, 422889a36810SAnil Ravindranath .slave_configure = pmcraid_slave_configure, 422989a36810SAnil Ravindranath .slave_destroy = pmcraid_slave_destroy, 423089a36810SAnil Ravindranath .change_queue_depth = pmcraid_change_queue_depth, 423189a36810SAnil Ravindranath .can_queue = PMCRAID_MAX_IO_CMD, 423289a36810SAnil Ravindranath .this_id = -1, 423389a36810SAnil Ravindranath .sg_tablesize = PMCRAID_MAX_IOADLS, 423489a36810SAnil Ravindranath .max_sectors = PMCRAID_IOA_MAX_SECTORS, 423554b2b50cSMartin K. Petersen .no_write_same = 1, 423689a36810SAnil Ravindranath .cmd_per_lun = PMCRAID_MAX_CMD_PER_LUN, 423789a36810SAnil Ravindranath .use_clustering = ENABLE_CLUSTERING, 423889a36810SAnil Ravindranath .shost_attrs = pmcraid_host_attrs, 42392ecb204dSChristoph Hellwig .proc_name = PMCRAID_DRIVER_NAME, 424089a36810SAnil Ravindranath }; 424189a36810SAnil Ravindranath 4242c20c4267SAnil Ravindranath /* 4243c20c4267SAnil Ravindranath * pmcraid_isr_msix - implements MSI-X interrupt handling routine 4244c20c4267SAnil Ravindranath * @irq: interrupt vector number 4245c20c4267SAnil Ravindranath * @dev_id: pointer hrrq_vector 424689a36810SAnil Ravindranath * 424789a36810SAnil Ravindranath * Return Value 4248c20c4267SAnil Ravindranath * IRQ_HANDLED if interrupt is handled or IRQ_NONE if ignored 424989a36810SAnil Ravindranath */ 425089a36810SAnil Ravindranath 4251c20c4267SAnil Ravindranath static irqreturn_t pmcraid_isr_msix(int irq, void *dev_id) 4252c20c4267SAnil Ravindranath { 4253c20c4267SAnil Ravindranath struct pmcraid_isr_param *hrrq_vector; 4254c20c4267SAnil Ravindranath struct pmcraid_instance *pinstance; 4255c20c4267SAnil Ravindranath unsigned long lock_flags; 4256c20c4267SAnil Ravindranath u32 intrs_val; 4257c20c4267SAnil Ravindranath int hrrq_id; 4258c20c4267SAnil Ravindranath 4259c20c4267SAnil Ravindranath hrrq_vector = (struct pmcraid_isr_param *)dev_id; 4260c20c4267SAnil Ravindranath hrrq_id = hrrq_vector->hrrq_id; 4261c20c4267SAnil Ravindranath pinstance = hrrq_vector->drv_inst; 4262c20c4267SAnil Ravindranath 4263c20c4267SAnil Ravindranath if (!hrrq_id) { 4264c20c4267SAnil Ravindranath /* Read the interrupt */ 4265c20c4267SAnil Ravindranath intrs_val = pmcraid_read_interrupts(pinstance); 4266c20c4267SAnil Ravindranath if (intrs_val && 4267c20c4267SAnil Ravindranath ((ioread32(pinstance->int_regs.host_ioa_interrupt_reg) 4268c20c4267SAnil Ravindranath & DOORBELL_INTR_MSIX_CLR) == 0)) { 4269c20c4267SAnil Ravindranath /* Any error interrupts including unit_check, 4270c20c4267SAnil Ravindranath * initiate IOA reset.In case of unit check indicate 4271c20c4267SAnil Ravindranath * to reset_sequence that IOA unit checked and prepare 4272c20c4267SAnil Ravindranath * for a dump during reset sequence 4273c20c4267SAnil Ravindranath */ 4274c20c4267SAnil Ravindranath if (intrs_val & PMCRAID_ERROR_INTERRUPTS) { 4275c20c4267SAnil Ravindranath if (intrs_val & INTRS_IOA_UNIT_CHECK) 4276c20c4267SAnil Ravindranath pinstance->ioa_unit_check = 1; 4277c20c4267SAnil Ravindranath 4278c20c4267SAnil Ravindranath pmcraid_err("ISR: error interrupts: %x \ 4279c20c4267SAnil Ravindranath initiating reset\n", intrs_val); 4280c20c4267SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, 4281c20c4267SAnil Ravindranath lock_flags); 4282c20c4267SAnil Ravindranath pmcraid_initiate_reset(pinstance); 4283c20c4267SAnil Ravindranath spin_unlock_irqrestore( 4284c20c4267SAnil Ravindranath pinstance->host->host_lock, 4285c20c4267SAnil Ravindranath lock_flags); 4286c20c4267SAnil Ravindranath } 4287c20c4267SAnil Ravindranath /* If interrupt was as part of the ioa initialization, 4288c20c4267SAnil Ravindranath * clear it. Delete the timer and wakeup the 4289c20c4267SAnil Ravindranath * reset engine to proceed with reset sequence 4290c20c4267SAnil Ravindranath */ 4291c20c4267SAnil Ravindranath if (intrs_val & INTRS_TRANSITION_TO_OPERATIONAL) 4292c20c4267SAnil Ravindranath pmcraid_clr_trans_op(pinstance); 4293c20c4267SAnil Ravindranath 4294c20c4267SAnil Ravindranath /* Clear the interrupt register by writing 4295c20c4267SAnil Ravindranath * to host to ioa doorbell. Once done 4296c20c4267SAnil Ravindranath * FW will clear the interrupt. 4297c20c4267SAnil Ravindranath */ 4298c20c4267SAnil Ravindranath iowrite32(DOORBELL_INTR_MSIX_CLR, 4299c20c4267SAnil Ravindranath pinstance->int_regs.host_ioa_interrupt_reg); 4300c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.host_ioa_interrupt_reg); 4301c20c4267SAnil Ravindranath 4302c20c4267SAnil Ravindranath 4303c20c4267SAnil Ravindranath } 4304c20c4267SAnil Ravindranath } 4305c20c4267SAnil Ravindranath 430689a36810SAnil Ravindranath tasklet_schedule(&(pinstance->isr_tasklet[hrrq_id])); 4307c20c4267SAnil Ravindranath 4308c20c4267SAnil Ravindranath return IRQ_HANDLED; 430989a36810SAnil Ravindranath } 431089a36810SAnil Ravindranath 431189a36810SAnil Ravindranath /** 4312c20c4267SAnil Ravindranath * pmcraid_isr - implements legacy interrupt handling routine 431389a36810SAnil Ravindranath * 431489a36810SAnil Ravindranath * @irq: interrupt vector number 431589a36810SAnil Ravindranath * @dev_id: pointer hrrq_vector 431689a36810SAnil Ravindranath * 431789a36810SAnil Ravindranath * Return Value 431889a36810SAnil Ravindranath * IRQ_HANDLED if interrupt is handled or IRQ_NONE if ignored 431989a36810SAnil Ravindranath */ 432089a36810SAnil Ravindranath static irqreturn_t pmcraid_isr(int irq, void *dev_id) 432189a36810SAnil Ravindranath { 432289a36810SAnil Ravindranath struct pmcraid_isr_param *hrrq_vector; 432389a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 432489a36810SAnil Ravindranath u32 intrs; 4325c20c4267SAnil Ravindranath unsigned long lock_flags; 4326c20c4267SAnil Ravindranath int hrrq_id = 0; 432789a36810SAnil Ravindranath 432889a36810SAnil Ravindranath /* In case of legacy interrupt mode where interrupts are shared across 432989a36810SAnil Ravindranath * isrs, it may be possible that the current interrupt is not from IOA 433089a36810SAnil Ravindranath */ 433189a36810SAnil Ravindranath if (!dev_id) { 433289a36810SAnil Ravindranath printk(KERN_INFO "%s(): NULL host pointer\n", __func__); 433389a36810SAnil Ravindranath return IRQ_NONE; 433489a36810SAnil Ravindranath } 433589a36810SAnil Ravindranath hrrq_vector = (struct pmcraid_isr_param *)dev_id; 433689a36810SAnil Ravindranath pinstance = hrrq_vector->drv_inst; 433789a36810SAnil Ravindranath 433889a36810SAnil Ravindranath intrs = pmcraid_read_interrupts(pinstance); 433989a36810SAnil Ravindranath 4340c20c4267SAnil Ravindranath if (unlikely((intrs & PMCRAID_PCI_INTERRUPTS) == 0)) 434189a36810SAnil Ravindranath return IRQ_NONE; 434289a36810SAnil Ravindranath 434389a36810SAnil Ravindranath /* Any error interrupts including unit_check, initiate IOA reset. 434489a36810SAnil Ravindranath * In case of unit check indicate to reset_sequence that IOA unit 434589a36810SAnil Ravindranath * checked and prepare for a dump during reset sequence 434689a36810SAnil Ravindranath */ 434789a36810SAnil Ravindranath if (intrs & PMCRAID_ERROR_INTERRUPTS) { 434889a36810SAnil Ravindranath 434989a36810SAnil Ravindranath if (intrs & INTRS_IOA_UNIT_CHECK) 435089a36810SAnil Ravindranath pinstance->ioa_unit_check = 1; 435189a36810SAnil Ravindranath 435289a36810SAnil Ravindranath iowrite32(intrs, 435389a36810SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_clr_reg); 435489a36810SAnil Ravindranath pmcraid_err("ISR: error interrupts: %x initiating reset\n", 435589a36810SAnil Ravindranath intrs); 4356c20c4267SAnil Ravindranath intrs = ioread32( 4357c20c4267SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_clr_reg); 4358c20c4267SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 435989a36810SAnil Ravindranath pmcraid_initiate_reset(pinstance); 436089a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 4361c20c4267SAnil Ravindranath } else { 4362c20c4267SAnil Ravindranath /* If interrupt was as part of the ioa initialization, 4363c20c4267SAnil Ravindranath * clear. Delete the timer and wakeup the 4364c20c4267SAnil Ravindranath * reset engine to proceed with reset sequence 4365c20c4267SAnil Ravindranath */ 4366c20c4267SAnil Ravindranath if (intrs & INTRS_TRANSITION_TO_OPERATIONAL) { 4367c20c4267SAnil Ravindranath pmcraid_clr_trans_op(pinstance); 4368c20c4267SAnil Ravindranath } else { 4369c20c4267SAnil Ravindranath iowrite32(intrs, 4370c20c4267SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_clr_reg); 4371c20c4267SAnil Ravindranath ioread32( 4372c20c4267SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_clr_reg); 4373c20c4267SAnil Ravindranath 4374c20c4267SAnil Ravindranath tasklet_schedule( 4375c20c4267SAnil Ravindranath &(pinstance->isr_tasklet[hrrq_id])); 4376c20c4267SAnil Ravindranath } 4377c20c4267SAnil Ravindranath } 437889a36810SAnil Ravindranath 437989a36810SAnil Ravindranath return IRQ_HANDLED; 438089a36810SAnil Ravindranath } 438189a36810SAnil Ravindranath 438289a36810SAnil Ravindranath 438389a36810SAnil Ravindranath /** 438489a36810SAnil Ravindranath * pmcraid_worker_function - worker thread function 438589a36810SAnil Ravindranath * 438689a36810SAnil Ravindranath * @workp: pointer to struct work queue 438789a36810SAnil Ravindranath * 438889a36810SAnil Ravindranath * Return Value 438989a36810SAnil Ravindranath * None 439089a36810SAnil Ravindranath */ 439189a36810SAnil Ravindranath 439289a36810SAnil Ravindranath static void pmcraid_worker_function(struct work_struct *workp) 439389a36810SAnil Ravindranath { 439489a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 439589a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 439689a36810SAnil Ravindranath struct pmcraid_resource_entry *temp; 439789a36810SAnil Ravindranath struct scsi_device *sdev; 439889a36810SAnil Ravindranath unsigned long lock_flags; 439989a36810SAnil Ravindranath unsigned long host_lock_flags; 4400c20c4267SAnil Ravindranath u16 fw_version; 440189a36810SAnil Ravindranath u8 bus, target, lun; 440289a36810SAnil Ravindranath 440389a36810SAnil Ravindranath pinstance = container_of(workp, struct pmcraid_instance, worker_q); 440489a36810SAnil Ravindranath /* add resources only after host is added into system */ 440589a36810SAnil Ravindranath if (!atomic_read(&pinstance->expose_resources)) 440689a36810SAnil Ravindranath return; 440789a36810SAnil Ravindranath 4408c20c4267SAnil Ravindranath fw_version = be16_to_cpu(pinstance->inq_data->fw_version); 4409c20c4267SAnil Ravindranath 441089a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->resource_lock, lock_flags); 441189a36810SAnil Ravindranath list_for_each_entry_safe(res, temp, &pinstance->used_res_q, queue) { 441289a36810SAnil Ravindranath 441389a36810SAnil Ravindranath if (res->change_detected == RES_CHANGE_DEL && res->scsi_dev) { 441489a36810SAnil Ravindranath sdev = res->scsi_dev; 441589a36810SAnil Ravindranath 441689a36810SAnil Ravindranath /* host_lock must be held before calling 441789a36810SAnil Ravindranath * scsi_device_get 441889a36810SAnil Ravindranath */ 441989a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, 442089a36810SAnil Ravindranath host_lock_flags); 442189a36810SAnil Ravindranath if (!scsi_device_get(sdev)) { 442289a36810SAnil Ravindranath spin_unlock_irqrestore( 442389a36810SAnil Ravindranath pinstance->host->host_lock, 442489a36810SAnil Ravindranath host_lock_flags); 442589a36810SAnil Ravindranath pmcraid_info("deleting %x from midlayer\n", 442689a36810SAnil Ravindranath res->cfg_entry.resource_address); 442789a36810SAnil Ravindranath list_move_tail(&res->queue, 442889a36810SAnil Ravindranath &pinstance->free_res_q); 442989a36810SAnil Ravindranath spin_unlock_irqrestore( 443089a36810SAnil Ravindranath &pinstance->resource_lock, 443189a36810SAnil Ravindranath lock_flags); 443289a36810SAnil Ravindranath scsi_remove_device(sdev); 443389a36810SAnil Ravindranath scsi_device_put(sdev); 443489a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->resource_lock, 443589a36810SAnil Ravindranath lock_flags); 443689a36810SAnil Ravindranath res->change_detected = 0; 443789a36810SAnil Ravindranath } else { 443889a36810SAnil Ravindranath spin_unlock_irqrestore( 443989a36810SAnil Ravindranath pinstance->host->host_lock, 444089a36810SAnil Ravindranath host_lock_flags); 444189a36810SAnil Ravindranath } 444289a36810SAnil Ravindranath } 444389a36810SAnil Ravindranath } 444489a36810SAnil Ravindranath 444589a36810SAnil Ravindranath list_for_each_entry(res, &pinstance->used_res_q, queue) { 444689a36810SAnil Ravindranath 444789a36810SAnil Ravindranath if (res->change_detected == RES_CHANGE_ADD) { 444889a36810SAnil Ravindranath 4449c20c4267SAnil Ravindranath if (!pmcraid_expose_resource(fw_version, 4450c20c4267SAnil Ravindranath &res->cfg_entry)) 445189a36810SAnil Ravindranath continue; 445289a36810SAnil Ravindranath 445389a36810SAnil Ravindranath if (RES_IS_VSET(res->cfg_entry)) { 445489a36810SAnil Ravindranath bus = PMCRAID_VSET_BUS_ID; 4455c20c4267SAnil Ravindranath if (fw_version <= PMCRAID_FW_VERSION_1) 445689a36810SAnil Ravindranath target = res->cfg_entry.unique_flags1; 4457c20c4267SAnil Ravindranath else 445845c80be6SArnd Bergmann target = le16_to_cpu(res->cfg_entry.array_id) & 0xFF; 445989a36810SAnil Ravindranath lun = PMCRAID_VSET_LUN_ID; 446089a36810SAnil Ravindranath } else { 446189a36810SAnil Ravindranath bus = PMCRAID_PHYS_BUS_ID; 446289a36810SAnil Ravindranath target = 446389a36810SAnil Ravindranath RES_TARGET( 446489a36810SAnil Ravindranath res->cfg_entry.resource_address); 446589a36810SAnil Ravindranath lun = RES_LUN(res->cfg_entry.resource_address); 446689a36810SAnil Ravindranath } 446789a36810SAnil Ravindranath 446889a36810SAnil Ravindranath res->change_detected = 0; 446989a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, 447089a36810SAnil Ravindranath lock_flags); 447189a36810SAnil Ravindranath scsi_add_device(pinstance->host, bus, target, lun); 447289a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->resource_lock, 447389a36810SAnil Ravindranath lock_flags); 447489a36810SAnil Ravindranath } 447589a36810SAnil Ravindranath } 447689a36810SAnil Ravindranath 447789a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); 447889a36810SAnil Ravindranath } 447989a36810SAnil Ravindranath 448089a36810SAnil Ravindranath /** 448189a36810SAnil Ravindranath * pmcraid_tasklet_function - Tasklet function 448289a36810SAnil Ravindranath * 448389a36810SAnil Ravindranath * @instance: pointer to msix param structure 448489a36810SAnil Ravindranath * 448589a36810SAnil Ravindranath * Return Value 448689a36810SAnil Ravindranath * None 448789a36810SAnil Ravindranath */ 4488c20c4267SAnil Ravindranath static void pmcraid_tasklet_function(unsigned long instance) 448989a36810SAnil Ravindranath { 449089a36810SAnil Ravindranath struct pmcraid_isr_param *hrrq_vector; 449189a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 449289a36810SAnil Ravindranath unsigned long hrrq_lock_flags; 449389a36810SAnil Ravindranath unsigned long pending_lock_flags; 449489a36810SAnil Ravindranath unsigned long host_lock_flags; 449589a36810SAnil Ravindranath spinlock_t *lockp; /* hrrq buffer lock */ 449689a36810SAnil Ravindranath int id; 449745c80be6SArnd Bergmann u32 resp; 449889a36810SAnil Ravindranath 449989a36810SAnil Ravindranath hrrq_vector = (struct pmcraid_isr_param *)instance; 450089a36810SAnil Ravindranath pinstance = hrrq_vector->drv_inst; 450189a36810SAnil Ravindranath id = hrrq_vector->hrrq_id; 450289a36810SAnil Ravindranath lockp = &(pinstance->hrrq_lock[id]); 450389a36810SAnil Ravindranath 450489a36810SAnil Ravindranath /* loop through each of the commands responded by IOA. Each HRRQ buf is 450589a36810SAnil Ravindranath * protected by its own lock. Traversals must be done within this lock 450689a36810SAnil Ravindranath * as there may be multiple tasklets running on multiple CPUs. Note 450789a36810SAnil Ravindranath * that the lock is held just for picking up the response handle and 450889a36810SAnil Ravindranath * manipulating hrrq_curr/toggle_bit values. 450989a36810SAnil Ravindranath */ 451089a36810SAnil Ravindranath spin_lock_irqsave(lockp, hrrq_lock_flags); 451189a36810SAnil Ravindranath 451289a36810SAnil Ravindranath resp = le32_to_cpu(*(pinstance->hrrq_curr[id])); 451389a36810SAnil Ravindranath 451489a36810SAnil Ravindranath while ((resp & HRRQ_TOGGLE_BIT) == 451589a36810SAnil Ravindranath pinstance->host_toggle_bit[id]) { 451689a36810SAnil Ravindranath 451789a36810SAnil Ravindranath int cmd_index = resp >> 2; 451889a36810SAnil Ravindranath struct pmcraid_cmd *cmd = NULL; 451989a36810SAnil Ravindranath 452089a36810SAnil Ravindranath if (pinstance->hrrq_curr[id] < pinstance->hrrq_end[id]) { 452189a36810SAnil Ravindranath pinstance->hrrq_curr[id]++; 452289a36810SAnil Ravindranath } else { 452389a36810SAnil Ravindranath pinstance->hrrq_curr[id] = pinstance->hrrq_start[id]; 452489a36810SAnil Ravindranath pinstance->host_toggle_bit[id] ^= 1u; 452589a36810SAnil Ravindranath } 452689a36810SAnil Ravindranath 4527c20c4267SAnil Ravindranath if (cmd_index >= PMCRAID_MAX_CMD) { 4528c20c4267SAnil Ravindranath /* In case of invalid response handle, log message */ 4529c20c4267SAnil Ravindranath pmcraid_err("Invalid response handle %d\n", cmd_index); 4530c20c4267SAnil Ravindranath resp = le32_to_cpu(*(pinstance->hrrq_curr[id])); 4531c20c4267SAnil Ravindranath continue; 4532c20c4267SAnil Ravindranath } 4533c20c4267SAnil Ravindranath 4534c20c4267SAnil Ravindranath cmd = pinstance->cmd_list[cmd_index]; 453589a36810SAnil Ravindranath spin_unlock_irqrestore(lockp, hrrq_lock_flags); 453689a36810SAnil Ravindranath 453789a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->pending_pool_lock, 453889a36810SAnil Ravindranath pending_lock_flags); 453989a36810SAnil Ravindranath list_del(&cmd->free_list); 454089a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->pending_pool_lock, 454189a36810SAnil Ravindranath pending_lock_flags); 454289a36810SAnil Ravindranath del_timer(&cmd->timer); 454389a36810SAnil Ravindranath atomic_dec(&pinstance->outstanding_cmds); 454489a36810SAnil Ravindranath 454589a36810SAnil Ravindranath if (cmd->cmd_done == pmcraid_ioa_reset) { 454689a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, 454789a36810SAnil Ravindranath host_lock_flags); 454889a36810SAnil Ravindranath cmd->cmd_done(cmd); 454989a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 455089a36810SAnil Ravindranath host_lock_flags); 455189a36810SAnil Ravindranath } else if (cmd->cmd_done != NULL) { 455289a36810SAnil Ravindranath cmd->cmd_done(cmd); 455389a36810SAnil Ravindranath } 455489a36810SAnil Ravindranath /* loop over until we are done with all responses */ 455589a36810SAnil Ravindranath spin_lock_irqsave(lockp, hrrq_lock_flags); 455689a36810SAnil Ravindranath resp = le32_to_cpu(*(pinstance->hrrq_curr[id])); 455789a36810SAnil Ravindranath } 455889a36810SAnil Ravindranath 455989a36810SAnil Ravindranath spin_unlock_irqrestore(lockp, hrrq_lock_flags); 456089a36810SAnil Ravindranath } 456189a36810SAnil Ravindranath 456289a36810SAnil Ravindranath /** 456389a36810SAnil Ravindranath * pmcraid_unregister_interrupt_handler - de-register interrupts handlers 456489a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 456589a36810SAnil Ravindranath * 456689a36810SAnil Ravindranath * This routine un-registers registered interrupt handler and 456789a36810SAnil Ravindranath * also frees irqs/vectors. 456889a36810SAnil Ravindranath * 456989a36810SAnil Ravindranath * Retun Value 457089a36810SAnil Ravindranath * None 457189a36810SAnil Ravindranath */ 457289a36810SAnil Ravindranath static 457389a36810SAnil Ravindranath void pmcraid_unregister_interrupt_handler(struct pmcraid_instance *pinstance) 457489a36810SAnil Ravindranath { 4575eab5c150SChristoph Hellwig struct pci_dev *pdev = pinstance->pdev; 4576c20c4267SAnil Ravindranath int i; 4577c20c4267SAnil Ravindranath 4578c20c4267SAnil Ravindranath for (i = 0; i < pinstance->num_hrrq; i++) 4579eab5c150SChristoph Hellwig free_irq(pci_irq_vector(pdev, i), &pinstance->hrrq_vector[i]); 4580c20c4267SAnil Ravindranath 4581c20c4267SAnil Ravindranath pinstance->interrupt_mode = 0; 4582eab5c150SChristoph Hellwig pci_free_irq_vectors(pdev); 458389a36810SAnil Ravindranath } 458489a36810SAnil Ravindranath 458589a36810SAnil Ravindranath /** 458689a36810SAnil Ravindranath * pmcraid_register_interrupt_handler - registers interrupt handler 458789a36810SAnil Ravindranath * @pinstance: pointer to per-adapter instance structure 458889a36810SAnil Ravindranath * 458989a36810SAnil Ravindranath * Return Value 459089a36810SAnil Ravindranath * 0 on success, non-zero error code otherwise. 459189a36810SAnil Ravindranath */ 459289a36810SAnil Ravindranath static int 459389a36810SAnil Ravindranath pmcraid_register_interrupt_handler(struct pmcraid_instance *pinstance) 459489a36810SAnil Ravindranath { 459589a36810SAnil Ravindranath struct pci_dev *pdev = pinstance->pdev; 4596eab5c150SChristoph Hellwig unsigned int irq_flag = PCI_IRQ_LEGACY, flag; 4597eab5c150SChristoph Hellwig int num_hrrq, rc, i; 4598eab5c150SChristoph Hellwig irq_handler_t isr; 459989a36810SAnil Ravindranath 4600eab5c150SChristoph Hellwig if (pmcraid_enable_msix) 4601eab5c150SChristoph Hellwig irq_flag |= PCI_IRQ_MSIX; 4602c20c4267SAnil Ravindranath 4603eab5c150SChristoph Hellwig num_hrrq = pci_alloc_irq_vectors(pdev, 1, PMCRAID_NUM_MSIX_VECTORS, 4604eab5c150SChristoph Hellwig irq_flag); 4605c01a8bc0SAlexander Gordeev if (num_hrrq < 0) 4606eab5c150SChristoph Hellwig return num_hrrq; 4607eab5c150SChristoph Hellwig 4608eab5c150SChristoph Hellwig if (pdev->msix_enabled) { 4609eab5c150SChristoph Hellwig flag = 0; 4610eab5c150SChristoph Hellwig isr = pmcraid_isr_msix; 4611eab5c150SChristoph Hellwig } else { 4612eab5c150SChristoph Hellwig flag = IRQF_SHARED; 4613eab5c150SChristoph Hellwig isr = pmcraid_isr; 4614eab5c150SChristoph Hellwig } 4615c20c4267SAnil Ravindranath 4616c20c4267SAnil Ravindranath for (i = 0; i < num_hrrq; i++) { 4617eab5c150SChristoph Hellwig struct pmcraid_isr_param *vec = &pinstance->hrrq_vector[i]; 4618c20c4267SAnil Ravindranath 4619eab5c150SChristoph Hellwig vec->hrrq_id = i; 4620eab5c150SChristoph Hellwig vec->drv_inst = pinstance; 4621eab5c150SChristoph Hellwig rc = request_irq(pci_irq_vector(pdev, i), isr, flag, 4622eab5c150SChristoph Hellwig PMCRAID_DRIVER_NAME, vec); 4623eab5c150SChristoph Hellwig if (rc) 4624eab5c150SChristoph Hellwig goto out_unwind; 4625c20c4267SAnil Ravindranath } 4626c20c4267SAnil Ravindranath 4627c20c4267SAnil Ravindranath pinstance->num_hrrq = num_hrrq; 4628eab5c150SChristoph Hellwig if (pdev->msix_enabled) { 4629c20c4267SAnil Ravindranath pinstance->interrupt_mode = 1; 4630c20c4267SAnil Ravindranath iowrite32(DOORBELL_INTR_MODE_MSIX, 4631c20c4267SAnil Ravindranath pinstance->int_regs.host_ioa_interrupt_reg); 4632c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.host_ioa_interrupt_reg); 4633c20c4267SAnil Ravindranath } 4634c20c4267SAnil Ravindranath 4635eab5c150SChristoph Hellwig return 0; 4636c20c4267SAnil Ravindranath 4637eab5c150SChristoph Hellwig out_unwind: 4638eab5c150SChristoph Hellwig while (--i > 0) 4639eab5c150SChristoph Hellwig free_irq(pci_irq_vector(pdev, i), &pinstance->hrrq_vector[i]); 4640eab5c150SChristoph Hellwig pci_free_irq_vectors(pdev); 4641c20c4267SAnil Ravindranath return rc; 464289a36810SAnil Ravindranath } 464389a36810SAnil Ravindranath 464489a36810SAnil Ravindranath /** 464589a36810SAnil Ravindranath * pmcraid_release_cmd_blocks - release buufers allocated for command blocks 464689a36810SAnil Ravindranath * @pinstance: per adapter instance structure pointer 464789a36810SAnil Ravindranath * @max_index: number of buffer blocks to release 464889a36810SAnil Ravindranath * 464989a36810SAnil Ravindranath * Return Value 465089a36810SAnil Ravindranath * None 465189a36810SAnil Ravindranath */ 465289a36810SAnil Ravindranath static void 465389a36810SAnil Ravindranath pmcraid_release_cmd_blocks(struct pmcraid_instance *pinstance, int max_index) 465489a36810SAnil Ravindranath { 465589a36810SAnil Ravindranath int i; 465689a36810SAnil Ravindranath for (i = 0; i < max_index; i++) { 465789a36810SAnil Ravindranath kmem_cache_free(pinstance->cmd_cachep, pinstance->cmd_list[i]); 465889a36810SAnil Ravindranath pinstance->cmd_list[i] = NULL; 465989a36810SAnil Ravindranath } 466089a36810SAnil Ravindranath kmem_cache_destroy(pinstance->cmd_cachep); 466189a36810SAnil Ravindranath pinstance->cmd_cachep = NULL; 466289a36810SAnil Ravindranath } 466389a36810SAnil Ravindranath 466489a36810SAnil Ravindranath /** 466589a36810SAnil Ravindranath * pmcraid_release_control_blocks - releases buffers alloced for control blocks 466689a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 466789a36810SAnil Ravindranath * @max_index: number of buffers (from 0 onwards) to release 466889a36810SAnil Ravindranath * 466989a36810SAnil Ravindranath * This function assumes that the command blocks for which control blocks are 467089a36810SAnil Ravindranath * linked are not released. 467189a36810SAnil Ravindranath * 467289a36810SAnil Ravindranath * Return Value 467389a36810SAnil Ravindranath * None 467489a36810SAnil Ravindranath */ 467589a36810SAnil Ravindranath static void 467689a36810SAnil Ravindranath pmcraid_release_control_blocks( 467789a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 467889a36810SAnil Ravindranath int max_index 467989a36810SAnil Ravindranath ) 468089a36810SAnil Ravindranath { 468189a36810SAnil Ravindranath int i; 468289a36810SAnil Ravindranath 468389a36810SAnil Ravindranath if (pinstance->control_pool == NULL) 468489a36810SAnil Ravindranath return; 468589a36810SAnil Ravindranath 468689a36810SAnil Ravindranath for (i = 0; i < max_index; i++) { 468789a36810SAnil Ravindranath pci_pool_free(pinstance->control_pool, 468889a36810SAnil Ravindranath pinstance->cmd_list[i]->ioa_cb, 468989a36810SAnil Ravindranath pinstance->cmd_list[i]->ioa_cb_bus_addr); 469089a36810SAnil Ravindranath pinstance->cmd_list[i]->ioa_cb = NULL; 469189a36810SAnil Ravindranath pinstance->cmd_list[i]->ioa_cb_bus_addr = 0; 469289a36810SAnil Ravindranath } 469389a36810SAnil Ravindranath pci_pool_destroy(pinstance->control_pool); 469489a36810SAnil Ravindranath pinstance->control_pool = NULL; 469589a36810SAnil Ravindranath } 469689a36810SAnil Ravindranath 469789a36810SAnil Ravindranath /** 469889a36810SAnil Ravindranath * pmcraid_allocate_cmd_blocks - allocate memory for cmd block structures 469989a36810SAnil Ravindranath * @pinstance - pointer to per adapter instance structure 470089a36810SAnil Ravindranath * 470189a36810SAnil Ravindranath * Allocates memory for command blocks using kernel slab allocator. 470289a36810SAnil Ravindranath * 470389a36810SAnil Ravindranath * Return Value 470489a36810SAnil Ravindranath * 0 in case of success; -ENOMEM in case of failure 470589a36810SAnil Ravindranath */ 47066f039790SGreg Kroah-Hartman static int pmcraid_allocate_cmd_blocks(struct pmcraid_instance *pinstance) 470789a36810SAnil Ravindranath { 470889a36810SAnil Ravindranath int i; 470989a36810SAnil Ravindranath 471089a36810SAnil Ravindranath sprintf(pinstance->cmd_pool_name, "pmcraid_cmd_pool_%d", 471189a36810SAnil Ravindranath pinstance->host->unique_id); 471289a36810SAnil Ravindranath 471389a36810SAnil Ravindranath 471489a36810SAnil Ravindranath pinstance->cmd_cachep = kmem_cache_create( 471589a36810SAnil Ravindranath pinstance->cmd_pool_name, 471689a36810SAnil Ravindranath sizeof(struct pmcraid_cmd), 0, 471789a36810SAnil Ravindranath SLAB_HWCACHE_ALIGN, NULL); 471889a36810SAnil Ravindranath if (!pinstance->cmd_cachep) 471989a36810SAnil Ravindranath return -ENOMEM; 472089a36810SAnil Ravindranath 472189a36810SAnil Ravindranath for (i = 0; i < PMCRAID_MAX_CMD; i++) { 472289a36810SAnil Ravindranath pinstance->cmd_list[i] = 472389a36810SAnil Ravindranath kmem_cache_alloc(pinstance->cmd_cachep, GFP_KERNEL); 472489a36810SAnil Ravindranath if (!pinstance->cmd_list[i]) { 472589a36810SAnil Ravindranath pmcraid_release_cmd_blocks(pinstance, i); 472689a36810SAnil Ravindranath return -ENOMEM; 472789a36810SAnil Ravindranath } 472889a36810SAnil Ravindranath } 472989a36810SAnil Ravindranath return 0; 473089a36810SAnil Ravindranath } 473189a36810SAnil Ravindranath 473289a36810SAnil Ravindranath /** 473389a36810SAnil Ravindranath * pmcraid_allocate_control_blocks - allocates memory control blocks 473489a36810SAnil Ravindranath * @pinstance : pointer to per adapter instance structure 473589a36810SAnil Ravindranath * 473689a36810SAnil Ravindranath * This function allocates PCI memory for DMAable buffers like IOARCB, IOADLs 473789a36810SAnil Ravindranath * and IOASAs. This is called after command blocks are already allocated. 473889a36810SAnil Ravindranath * 473989a36810SAnil Ravindranath * Return Value 474089a36810SAnil Ravindranath * 0 in case it can allocate all control blocks, otherwise -ENOMEM 474189a36810SAnil Ravindranath */ 47426f039790SGreg Kroah-Hartman static int pmcraid_allocate_control_blocks(struct pmcraid_instance *pinstance) 474389a36810SAnil Ravindranath { 474489a36810SAnil Ravindranath int i; 474589a36810SAnil Ravindranath 474689a36810SAnil Ravindranath sprintf(pinstance->ctl_pool_name, "pmcraid_control_pool_%d", 474789a36810SAnil Ravindranath pinstance->host->unique_id); 474889a36810SAnil Ravindranath 474989a36810SAnil Ravindranath pinstance->control_pool = 475089a36810SAnil Ravindranath pci_pool_create(pinstance->ctl_pool_name, 475189a36810SAnil Ravindranath pinstance->pdev, 475289a36810SAnil Ravindranath sizeof(struct pmcraid_control_block), 475389a36810SAnil Ravindranath PMCRAID_IOARCB_ALIGNMENT, 0); 475489a36810SAnil Ravindranath 475589a36810SAnil Ravindranath if (!pinstance->control_pool) 475689a36810SAnil Ravindranath return -ENOMEM; 475789a36810SAnil Ravindranath 475889a36810SAnil Ravindranath for (i = 0; i < PMCRAID_MAX_CMD; i++) { 475989a36810SAnil Ravindranath pinstance->cmd_list[i]->ioa_cb = 476089a36810SAnil Ravindranath pci_pool_alloc( 476189a36810SAnil Ravindranath pinstance->control_pool, 476289a36810SAnil Ravindranath GFP_KERNEL, 476389a36810SAnil Ravindranath &(pinstance->cmd_list[i]->ioa_cb_bus_addr)); 476489a36810SAnil Ravindranath 476589a36810SAnil Ravindranath if (!pinstance->cmd_list[i]->ioa_cb) { 476689a36810SAnil Ravindranath pmcraid_release_control_blocks(pinstance, i); 476789a36810SAnil Ravindranath return -ENOMEM; 476889a36810SAnil Ravindranath } 476989a36810SAnil Ravindranath memset(pinstance->cmd_list[i]->ioa_cb, 0, 477089a36810SAnil Ravindranath sizeof(struct pmcraid_control_block)); 477189a36810SAnil Ravindranath } 477289a36810SAnil Ravindranath return 0; 477389a36810SAnil Ravindranath } 477489a36810SAnil Ravindranath 477589a36810SAnil Ravindranath /** 477689a36810SAnil Ravindranath * pmcraid_release_host_rrqs - release memory allocated for hrrq buffer(s) 477789a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 477889a36810SAnil Ravindranath * @maxindex: size of hrrq buffer pointer array 477989a36810SAnil Ravindranath * 478089a36810SAnil Ravindranath * Return Value 478189a36810SAnil Ravindranath * None 478289a36810SAnil Ravindranath */ 478389a36810SAnil Ravindranath static void 478489a36810SAnil Ravindranath pmcraid_release_host_rrqs(struct pmcraid_instance *pinstance, int maxindex) 478589a36810SAnil Ravindranath { 478689a36810SAnil Ravindranath int i; 478789a36810SAnil Ravindranath for (i = 0; i < maxindex; i++) { 478889a36810SAnil Ravindranath 478989a36810SAnil Ravindranath pci_free_consistent(pinstance->pdev, 479089a36810SAnil Ravindranath HRRQ_ENTRY_SIZE * PMCRAID_MAX_CMD, 479189a36810SAnil Ravindranath pinstance->hrrq_start[i], 479289a36810SAnil Ravindranath pinstance->hrrq_start_bus_addr[i]); 479389a36810SAnil Ravindranath 479489a36810SAnil Ravindranath /* reset pointers and toggle bit to zeros */ 479589a36810SAnil Ravindranath pinstance->hrrq_start[i] = NULL; 479689a36810SAnil Ravindranath pinstance->hrrq_start_bus_addr[i] = 0; 479789a36810SAnil Ravindranath pinstance->host_toggle_bit[i] = 0; 479889a36810SAnil Ravindranath } 479989a36810SAnil Ravindranath } 480089a36810SAnil Ravindranath 480189a36810SAnil Ravindranath /** 480289a36810SAnil Ravindranath * pmcraid_allocate_host_rrqs - Allocate and initialize host RRQ buffers 480389a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 480489a36810SAnil Ravindranath * 480589a36810SAnil Ravindranath * Return value 480689a36810SAnil Ravindranath * 0 hrrq buffers are allocated, -ENOMEM otherwise. 480789a36810SAnil Ravindranath */ 48086f039790SGreg Kroah-Hartman static int pmcraid_allocate_host_rrqs(struct pmcraid_instance *pinstance) 480989a36810SAnil Ravindranath { 4810c20c4267SAnil Ravindranath int i, buffer_size; 4811c20c4267SAnil Ravindranath 4812c20c4267SAnil Ravindranath buffer_size = HRRQ_ENTRY_SIZE * PMCRAID_MAX_CMD; 481389a36810SAnil Ravindranath 481489a36810SAnil Ravindranath for (i = 0; i < pinstance->num_hrrq; i++) { 481589a36810SAnil Ravindranath pinstance->hrrq_start[i] = 481689a36810SAnil Ravindranath pci_alloc_consistent( 481789a36810SAnil Ravindranath pinstance->pdev, 481889a36810SAnil Ravindranath buffer_size, 481989a36810SAnil Ravindranath &(pinstance->hrrq_start_bus_addr[i])); 482089a36810SAnil Ravindranath 482189a36810SAnil Ravindranath if (pinstance->hrrq_start[i] == 0) { 4822c20c4267SAnil Ravindranath pmcraid_err("pci_alloc failed for hrrq vector : %d\n", 4823c20c4267SAnil Ravindranath i); 482489a36810SAnil Ravindranath pmcraid_release_host_rrqs(pinstance, i); 482589a36810SAnil Ravindranath return -ENOMEM; 482689a36810SAnil Ravindranath } 482789a36810SAnil Ravindranath 482889a36810SAnil Ravindranath memset(pinstance->hrrq_start[i], 0, buffer_size); 482989a36810SAnil Ravindranath pinstance->hrrq_curr[i] = pinstance->hrrq_start[i]; 483089a36810SAnil Ravindranath pinstance->hrrq_end[i] = 4831c20c4267SAnil Ravindranath pinstance->hrrq_start[i] + PMCRAID_MAX_CMD - 1; 483289a36810SAnil Ravindranath pinstance->host_toggle_bit[i] = 1; 483389a36810SAnil Ravindranath spin_lock_init(&pinstance->hrrq_lock[i]); 483489a36810SAnil Ravindranath } 483589a36810SAnil Ravindranath return 0; 483689a36810SAnil Ravindranath } 483789a36810SAnil Ravindranath 483889a36810SAnil Ravindranath /** 483989a36810SAnil Ravindranath * pmcraid_release_hcams - release HCAM buffers 484089a36810SAnil Ravindranath * 484189a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 484289a36810SAnil Ravindranath * 484389a36810SAnil Ravindranath * Return value 484489a36810SAnil Ravindranath * none 484589a36810SAnil Ravindranath */ 484689a36810SAnil Ravindranath static void pmcraid_release_hcams(struct pmcraid_instance *pinstance) 484789a36810SAnil Ravindranath { 484889a36810SAnil Ravindranath if (pinstance->ccn.msg != NULL) { 484989a36810SAnil Ravindranath pci_free_consistent(pinstance->pdev, 485089a36810SAnil Ravindranath PMCRAID_AEN_HDR_SIZE + 4851c20c4267SAnil Ravindranath sizeof(struct pmcraid_hcam_ccn_ext), 485289a36810SAnil Ravindranath pinstance->ccn.msg, 485389a36810SAnil Ravindranath pinstance->ccn.baddr); 485489a36810SAnil Ravindranath 485589a36810SAnil Ravindranath pinstance->ccn.msg = NULL; 485689a36810SAnil Ravindranath pinstance->ccn.hcam = NULL; 485789a36810SAnil Ravindranath pinstance->ccn.baddr = 0; 485889a36810SAnil Ravindranath } 485989a36810SAnil Ravindranath 486089a36810SAnil Ravindranath if (pinstance->ldn.msg != NULL) { 486189a36810SAnil Ravindranath pci_free_consistent(pinstance->pdev, 486289a36810SAnil Ravindranath PMCRAID_AEN_HDR_SIZE + 486389a36810SAnil Ravindranath sizeof(struct pmcraid_hcam_ldn), 486489a36810SAnil Ravindranath pinstance->ldn.msg, 486589a36810SAnil Ravindranath pinstance->ldn.baddr); 486689a36810SAnil Ravindranath 486789a36810SAnil Ravindranath pinstance->ldn.msg = NULL; 486889a36810SAnil Ravindranath pinstance->ldn.hcam = NULL; 486989a36810SAnil Ravindranath pinstance->ldn.baddr = 0; 487089a36810SAnil Ravindranath } 487189a36810SAnil Ravindranath } 487289a36810SAnil Ravindranath 487389a36810SAnil Ravindranath /** 487489a36810SAnil Ravindranath * pmcraid_allocate_hcams - allocates HCAM buffers 487589a36810SAnil Ravindranath * @pinstance : pointer to per adapter instance structure 487689a36810SAnil Ravindranath * 487789a36810SAnil Ravindranath * Return Value: 487889a36810SAnil Ravindranath * 0 in case of successful allocation, non-zero otherwise 487989a36810SAnil Ravindranath */ 488089a36810SAnil Ravindranath static int pmcraid_allocate_hcams(struct pmcraid_instance *pinstance) 488189a36810SAnil Ravindranath { 488289a36810SAnil Ravindranath pinstance->ccn.msg = pci_alloc_consistent( 488389a36810SAnil Ravindranath pinstance->pdev, 488489a36810SAnil Ravindranath PMCRAID_AEN_HDR_SIZE + 4885c20c4267SAnil Ravindranath sizeof(struct pmcraid_hcam_ccn_ext), 488689a36810SAnil Ravindranath &(pinstance->ccn.baddr)); 488789a36810SAnil Ravindranath 488889a36810SAnil Ravindranath pinstance->ldn.msg = pci_alloc_consistent( 488989a36810SAnil Ravindranath pinstance->pdev, 489089a36810SAnil Ravindranath PMCRAID_AEN_HDR_SIZE + 489189a36810SAnil Ravindranath sizeof(struct pmcraid_hcam_ldn), 489289a36810SAnil Ravindranath &(pinstance->ldn.baddr)); 489389a36810SAnil Ravindranath 489489a36810SAnil Ravindranath if (pinstance->ldn.msg == NULL || pinstance->ccn.msg == NULL) { 489589a36810SAnil Ravindranath pmcraid_release_hcams(pinstance); 489689a36810SAnil Ravindranath } else { 489789a36810SAnil Ravindranath pinstance->ccn.hcam = 489889a36810SAnil Ravindranath (void *)pinstance->ccn.msg + PMCRAID_AEN_HDR_SIZE; 489989a36810SAnil Ravindranath pinstance->ldn.hcam = 490089a36810SAnil Ravindranath (void *)pinstance->ldn.msg + PMCRAID_AEN_HDR_SIZE; 490189a36810SAnil Ravindranath 490289a36810SAnil Ravindranath atomic_set(&pinstance->ccn.ignore, 0); 490389a36810SAnil Ravindranath atomic_set(&pinstance->ldn.ignore, 0); 490489a36810SAnil Ravindranath } 490589a36810SAnil Ravindranath 490689a36810SAnil Ravindranath return (pinstance->ldn.msg == NULL) ? -ENOMEM : 0; 490789a36810SAnil Ravindranath } 490889a36810SAnil Ravindranath 490989a36810SAnil Ravindranath /** 491089a36810SAnil Ravindranath * pmcraid_release_config_buffers - release config.table buffers 491189a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 491289a36810SAnil Ravindranath * 491389a36810SAnil Ravindranath * Return Value 491489a36810SAnil Ravindranath * none 491589a36810SAnil Ravindranath */ 491689a36810SAnil Ravindranath static void pmcraid_release_config_buffers(struct pmcraid_instance *pinstance) 491789a36810SAnil Ravindranath { 491889a36810SAnil Ravindranath if (pinstance->cfg_table != NULL && 491989a36810SAnil Ravindranath pinstance->cfg_table_bus_addr != 0) { 492089a36810SAnil Ravindranath pci_free_consistent(pinstance->pdev, 492189a36810SAnil Ravindranath sizeof(struct pmcraid_config_table), 492289a36810SAnil Ravindranath pinstance->cfg_table, 492389a36810SAnil Ravindranath pinstance->cfg_table_bus_addr); 492489a36810SAnil Ravindranath pinstance->cfg_table = NULL; 492589a36810SAnil Ravindranath pinstance->cfg_table_bus_addr = 0; 492689a36810SAnil Ravindranath } 492789a36810SAnil Ravindranath 492889a36810SAnil Ravindranath if (pinstance->res_entries != NULL) { 492989a36810SAnil Ravindranath int i; 493089a36810SAnil Ravindranath 493189a36810SAnil Ravindranath for (i = 0; i < PMCRAID_MAX_RESOURCES; i++) 493289a36810SAnil Ravindranath list_del(&pinstance->res_entries[i].queue); 493389a36810SAnil Ravindranath kfree(pinstance->res_entries); 493489a36810SAnil Ravindranath pinstance->res_entries = NULL; 493589a36810SAnil Ravindranath } 493689a36810SAnil Ravindranath 493789a36810SAnil Ravindranath pmcraid_release_hcams(pinstance); 493889a36810SAnil Ravindranath } 493989a36810SAnil Ravindranath 494089a36810SAnil Ravindranath /** 494189a36810SAnil Ravindranath * pmcraid_allocate_config_buffers - allocates DMAable memory for config table 494289a36810SAnil Ravindranath * @pinstance : pointer to per adapter instance structure 494389a36810SAnil Ravindranath * 494489a36810SAnil Ravindranath * Return Value 494589a36810SAnil Ravindranath * 0 for successful allocation, -ENOMEM for any failure 494689a36810SAnil Ravindranath */ 49476f039790SGreg Kroah-Hartman static int pmcraid_allocate_config_buffers(struct pmcraid_instance *pinstance) 494889a36810SAnil Ravindranath { 494989a36810SAnil Ravindranath int i; 495089a36810SAnil Ravindranath 495189a36810SAnil Ravindranath pinstance->res_entries = 495289a36810SAnil Ravindranath kzalloc(sizeof(struct pmcraid_resource_entry) * 495389a36810SAnil Ravindranath PMCRAID_MAX_RESOURCES, GFP_KERNEL); 495489a36810SAnil Ravindranath 495589a36810SAnil Ravindranath if (NULL == pinstance->res_entries) { 495689a36810SAnil Ravindranath pmcraid_err("failed to allocate memory for resource table\n"); 495789a36810SAnil Ravindranath return -ENOMEM; 495889a36810SAnil Ravindranath } 495989a36810SAnil Ravindranath 496089a36810SAnil Ravindranath for (i = 0; i < PMCRAID_MAX_RESOURCES; i++) 496189a36810SAnil Ravindranath list_add_tail(&pinstance->res_entries[i].queue, 496289a36810SAnil Ravindranath &pinstance->free_res_q); 496389a36810SAnil Ravindranath 496489a36810SAnil Ravindranath pinstance->cfg_table = 496589a36810SAnil Ravindranath pci_alloc_consistent(pinstance->pdev, 496689a36810SAnil Ravindranath sizeof(struct pmcraid_config_table), 496789a36810SAnil Ravindranath &pinstance->cfg_table_bus_addr); 496889a36810SAnil Ravindranath 496989a36810SAnil Ravindranath if (NULL == pinstance->cfg_table) { 497089a36810SAnil Ravindranath pmcraid_err("couldn't alloc DMA memory for config table\n"); 497189a36810SAnil Ravindranath pmcraid_release_config_buffers(pinstance); 497289a36810SAnil Ravindranath return -ENOMEM; 497389a36810SAnil Ravindranath } 497489a36810SAnil Ravindranath 497589a36810SAnil Ravindranath if (pmcraid_allocate_hcams(pinstance)) { 497689a36810SAnil Ravindranath pmcraid_err("could not alloc DMA memory for HCAMS\n"); 497789a36810SAnil Ravindranath pmcraid_release_config_buffers(pinstance); 497889a36810SAnil Ravindranath return -ENOMEM; 497989a36810SAnil Ravindranath } 498089a36810SAnil Ravindranath 498189a36810SAnil Ravindranath return 0; 498289a36810SAnil Ravindranath } 498389a36810SAnil Ravindranath 498489a36810SAnil Ravindranath /** 498589a36810SAnil Ravindranath * pmcraid_init_tasklets - registers tasklets for response handling 498689a36810SAnil Ravindranath * 498789a36810SAnil Ravindranath * @pinstance: pointer adapter instance structure 498889a36810SAnil Ravindranath * 498989a36810SAnil Ravindranath * Return value 499089a36810SAnil Ravindranath * none 499189a36810SAnil Ravindranath */ 499289a36810SAnil Ravindranath static void pmcraid_init_tasklets(struct pmcraid_instance *pinstance) 499389a36810SAnil Ravindranath { 499489a36810SAnil Ravindranath int i; 499589a36810SAnil Ravindranath for (i = 0; i < pinstance->num_hrrq; i++) 499689a36810SAnil Ravindranath tasklet_init(&pinstance->isr_tasklet[i], 499789a36810SAnil Ravindranath pmcraid_tasklet_function, 499889a36810SAnil Ravindranath (unsigned long)&pinstance->hrrq_vector[i]); 499989a36810SAnil Ravindranath } 500089a36810SAnil Ravindranath 500189a36810SAnil Ravindranath /** 500289a36810SAnil Ravindranath * pmcraid_kill_tasklets - destroys tasklets registered for response handling 500389a36810SAnil Ravindranath * 500489a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 500589a36810SAnil Ravindranath * 500689a36810SAnil Ravindranath * Return value 500789a36810SAnil Ravindranath * none 500889a36810SAnil Ravindranath */ 500989a36810SAnil Ravindranath static void pmcraid_kill_tasklets(struct pmcraid_instance *pinstance) 501089a36810SAnil Ravindranath { 501189a36810SAnil Ravindranath int i; 501289a36810SAnil Ravindranath for (i = 0; i < pinstance->num_hrrq; i++) 501389a36810SAnil Ravindranath tasklet_kill(&pinstance->isr_tasklet[i]); 501489a36810SAnil Ravindranath } 501589a36810SAnil Ravindranath 501689a36810SAnil Ravindranath /** 5017c20c4267SAnil Ravindranath * pmcraid_release_buffers - release per-adapter buffers allocated 5018c20c4267SAnil Ravindranath * 5019c20c4267SAnil Ravindranath * @pinstance: pointer to adapter soft state 5020c20c4267SAnil Ravindranath * 5021c20c4267SAnil Ravindranath * Return Value 5022c20c4267SAnil Ravindranath * none 5023c20c4267SAnil Ravindranath */ 5024c20c4267SAnil Ravindranath static void pmcraid_release_buffers(struct pmcraid_instance *pinstance) 5025c20c4267SAnil Ravindranath { 5026c20c4267SAnil Ravindranath pmcraid_release_config_buffers(pinstance); 5027c20c4267SAnil Ravindranath pmcraid_release_control_blocks(pinstance, PMCRAID_MAX_CMD); 5028c20c4267SAnil Ravindranath pmcraid_release_cmd_blocks(pinstance, PMCRAID_MAX_CMD); 5029c20c4267SAnil Ravindranath pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); 5030c20c4267SAnil Ravindranath 5031c20c4267SAnil Ravindranath if (pinstance->inq_data != NULL) { 5032c20c4267SAnil Ravindranath pci_free_consistent(pinstance->pdev, 5033c20c4267SAnil Ravindranath sizeof(struct pmcraid_inquiry_data), 5034c20c4267SAnil Ravindranath pinstance->inq_data, 5035c20c4267SAnil Ravindranath pinstance->inq_data_baddr); 5036c20c4267SAnil Ravindranath 5037c20c4267SAnil Ravindranath pinstance->inq_data = NULL; 5038c20c4267SAnil Ravindranath pinstance->inq_data_baddr = 0; 5039c20c4267SAnil Ravindranath } 5040592488a3SAnil Ravindranath 5041592488a3SAnil Ravindranath if (pinstance->timestamp_data != NULL) { 5042592488a3SAnil Ravindranath pci_free_consistent(pinstance->pdev, 5043592488a3SAnil Ravindranath sizeof(struct pmcraid_timestamp_data), 5044592488a3SAnil Ravindranath pinstance->timestamp_data, 5045592488a3SAnil Ravindranath pinstance->timestamp_data_baddr); 5046592488a3SAnil Ravindranath 5047592488a3SAnil Ravindranath pinstance->timestamp_data = NULL; 5048592488a3SAnil Ravindranath pinstance->timestamp_data_baddr = 0; 5049592488a3SAnil Ravindranath } 5050c20c4267SAnil Ravindranath } 5051c20c4267SAnil Ravindranath 5052c20c4267SAnil Ravindranath /** 505389a36810SAnil Ravindranath * pmcraid_init_buffers - allocates memory and initializes various structures 505489a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 505589a36810SAnil Ravindranath * 505689a36810SAnil Ravindranath * This routine pre-allocates memory based on the type of block as below: 505789a36810SAnil Ravindranath * cmdblocks(PMCRAID_MAX_CMD): kernel memory using kernel's slab_allocator, 505889a36810SAnil Ravindranath * IOARCBs(PMCRAID_MAX_CMD) : DMAable memory, using pci pool allocator 505989a36810SAnil Ravindranath * config-table entries : DMAable memory using pci_alloc_consistent 506089a36810SAnil Ravindranath * HostRRQs : DMAable memory, using pci_alloc_consistent 506189a36810SAnil Ravindranath * 506289a36810SAnil Ravindranath * Return Value 506389a36810SAnil Ravindranath * 0 in case all of the blocks are allocated, -ENOMEM otherwise. 506489a36810SAnil Ravindranath */ 50656f039790SGreg Kroah-Hartman static int pmcraid_init_buffers(struct pmcraid_instance *pinstance) 506689a36810SAnil Ravindranath { 506789a36810SAnil Ravindranath int i; 506889a36810SAnil Ravindranath 506989a36810SAnil Ravindranath if (pmcraid_allocate_host_rrqs(pinstance)) { 507089a36810SAnil Ravindranath pmcraid_err("couldn't allocate memory for %d host rrqs\n", 507189a36810SAnil Ravindranath pinstance->num_hrrq); 507289a36810SAnil Ravindranath return -ENOMEM; 507389a36810SAnil Ravindranath } 507489a36810SAnil Ravindranath 507589a36810SAnil Ravindranath if (pmcraid_allocate_config_buffers(pinstance)) { 507689a36810SAnil Ravindranath pmcraid_err("couldn't allocate memory for config buffers\n"); 507789a36810SAnil Ravindranath pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); 507889a36810SAnil Ravindranath return -ENOMEM; 507989a36810SAnil Ravindranath } 508089a36810SAnil Ravindranath 508189a36810SAnil Ravindranath if (pmcraid_allocate_cmd_blocks(pinstance)) { 508289a36810SAnil Ravindranath pmcraid_err("couldn't allocate memory for cmd blocks\n"); 508389a36810SAnil Ravindranath pmcraid_release_config_buffers(pinstance); 508489a36810SAnil Ravindranath pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); 508589a36810SAnil Ravindranath return -ENOMEM; 508689a36810SAnil Ravindranath } 508789a36810SAnil Ravindranath 508889a36810SAnil Ravindranath if (pmcraid_allocate_control_blocks(pinstance)) { 508989a36810SAnil Ravindranath pmcraid_err("couldn't allocate memory control blocks\n"); 509089a36810SAnil Ravindranath pmcraid_release_config_buffers(pinstance); 509189a36810SAnil Ravindranath pmcraid_release_cmd_blocks(pinstance, PMCRAID_MAX_CMD); 509289a36810SAnil Ravindranath pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); 509389a36810SAnil Ravindranath return -ENOMEM; 509489a36810SAnil Ravindranath } 509589a36810SAnil Ravindranath 5096c20c4267SAnil Ravindranath /* allocate DMAable memory for page D0 INQUIRY buffer */ 5097c20c4267SAnil Ravindranath pinstance->inq_data = pci_alloc_consistent( 5098c20c4267SAnil Ravindranath pinstance->pdev, 5099c20c4267SAnil Ravindranath sizeof(struct pmcraid_inquiry_data), 5100c20c4267SAnil Ravindranath &pinstance->inq_data_baddr); 5101c20c4267SAnil Ravindranath 5102c20c4267SAnil Ravindranath if (pinstance->inq_data == NULL) { 5103c20c4267SAnil Ravindranath pmcraid_err("couldn't allocate DMA memory for INQUIRY\n"); 5104c20c4267SAnil Ravindranath pmcraid_release_buffers(pinstance); 5105c20c4267SAnil Ravindranath return -ENOMEM; 5106c20c4267SAnil Ravindranath } 5107c20c4267SAnil Ravindranath 5108592488a3SAnil Ravindranath /* allocate DMAable memory for set timestamp data buffer */ 5109592488a3SAnil Ravindranath pinstance->timestamp_data = pci_alloc_consistent( 5110592488a3SAnil Ravindranath pinstance->pdev, 5111592488a3SAnil Ravindranath sizeof(struct pmcraid_timestamp_data), 5112592488a3SAnil Ravindranath &pinstance->timestamp_data_baddr); 5113592488a3SAnil Ravindranath 5114592488a3SAnil Ravindranath if (pinstance->timestamp_data == NULL) { 5115592488a3SAnil Ravindranath pmcraid_err("couldn't allocate DMA memory for \ 5116592488a3SAnil Ravindranath set time_stamp \n"); 5117592488a3SAnil Ravindranath pmcraid_release_buffers(pinstance); 5118592488a3SAnil Ravindranath return -ENOMEM; 5119592488a3SAnil Ravindranath } 5120592488a3SAnil Ravindranath 5121592488a3SAnil Ravindranath 512289a36810SAnil Ravindranath /* Initialize all the command blocks and add them to free pool. No 512389a36810SAnil Ravindranath * need to lock (free_pool_lock) as this is done in initialization 512489a36810SAnil Ravindranath * itself 512589a36810SAnil Ravindranath */ 512689a36810SAnil Ravindranath for (i = 0; i < PMCRAID_MAX_CMD; i++) { 512789a36810SAnil Ravindranath struct pmcraid_cmd *cmdp = pinstance->cmd_list[i]; 512889a36810SAnil Ravindranath pmcraid_init_cmdblk(cmdp, i); 512989a36810SAnil Ravindranath cmdp->drv_inst = pinstance; 513089a36810SAnil Ravindranath list_add_tail(&cmdp->free_list, &pinstance->free_cmd_pool); 513189a36810SAnil Ravindranath } 513289a36810SAnil Ravindranath 513389a36810SAnil Ravindranath return 0; 513489a36810SAnil Ravindranath } 513589a36810SAnil Ravindranath 513689a36810SAnil Ravindranath /** 513789a36810SAnil Ravindranath * pmcraid_reinit_buffers - resets various buffer pointers 513889a36810SAnil Ravindranath * @pinstance: pointer to adapter instance 513989a36810SAnil Ravindranath * Return value 514089a36810SAnil Ravindranath * none 514189a36810SAnil Ravindranath */ 514289a36810SAnil Ravindranath static void pmcraid_reinit_buffers(struct pmcraid_instance *pinstance) 514389a36810SAnil Ravindranath { 514489a36810SAnil Ravindranath int i; 514589a36810SAnil Ravindranath int buffer_size = HRRQ_ENTRY_SIZE * PMCRAID_MAX_CMD; 514689a36810SAnil Ravindranath 514789a36810SAnil Ravindranath for (i = 0; i < pinstance->num_hrrq; i++) { 514889a36810SAnil Ravindranath memset(pinstance->hrrq_start[i], 0, buffer_size); 514989a36810SAnil Ravindranath pinstance->hrrq_curr[i] = pinstance->hrrq_start[i]; 515089a36810SAnil Ravindranath pinstance->hrrq_end[i] = 515189a36810SAnil Ravindranath pinstance->hrrq_start[i] + PMCRAID_MAX_CMD - 1; 515289a36810SAnil Ravindranath pinstance->host_toggle_bit[i] = 1; 515389a36810SAnil Ravindranath } 515489a36810SAnil Ravindranath } 515589a36810SAnil Ravindranath 515689a36810SAnil Ravindranath /** 515789a36810SAnil Ravindranath * pmcraid_init_instance - initialize per instance data structure 515889a36810SAnil Ravindranath * @pdev: pointer to pci device structure 515989a36810SAnil Ravindranath * @host: pointer to Scsi_Host structure 516089a36810SAnil Ravindranath * @mapped_pci_addr: memory mapped IOA configuration registers 516189a36810SAnil Ravindranath * 516289a36810SAnil Ravindranath * Return Value 516389a36810SAnil Ravindranath * 0 on success, non-zero in case of any failure 516489a36810SAnil Ravindranath */ 51656f039790SGreg Kroah-Hartman static int pmcraid_init_instance(struct pci_dev *pdev, struct Scsi_Host *host, 51666f039790SGreg Kroah-Hartman void __iomem *mapped_pci_addr) 516789a36810SAnil Ravindranath { 516889a36810SAnil Ravindranath struct pmcraid_instance *pinstance = 516989a36810SAnil Ravindranath (struct pmcraid_instance *)host->hostdata; 517089a36810SAnil Ravindranath 517189a36810SAnil Ravindranath pinstance->host = host; 517289a36810SAnil Ravindranath pinstance->pdev = pdev; 517389a36810SAnil Ravindranath 517489a36810SAnil Ravindranath /* Initialize register addresses */ 517589a36810SAnil Ravindranath pinstance->mapped_dma_addr = mapped_pci_addr; 517689a36810SAnil Ravindranath 517789a36810SAnil Ravindranath /* Initialize chip-specific details */ 517889a36810SAnil Ravindranath { 517989a36810SAnil Ravindranath struct pmcraid_chip_details *chip_cfg = pinstance->chip_cfg; 518089a36810SAnil Ravindranath struct pmcraid_interrupts *pint_regs = &pinstance->int_regs; 518189a36810SAnil Ravindranath 518289a36810SAnil Ravindranath pinstance->ioarrin = mapped_pci_addr + chip_cfg->ioarrin; 518389a36810SAnil Ravindranath 518489a36810SAnil Ravindranath pint_regs->ioa_host_interrupt_reg = 518589a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->ioa_host_intr; 518689a36810SAnil Ravindranath pint_regs->ioa_host_interrupt_clr_reg = 518789a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->ioa_host_intr_clr; 5188c20c4267SAnil Ravindranath pint_regs->ioa_host_msix_interrupt_reg = 5189c20c4267SAnil Ravindranath mapped_pci_addr + chip_cfg->ioa_host_msix_intr; 519089a36810SAnil Ravindranath pint_regs->host_ioa_interrupt_reg = 519189a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->host_ioa_intr; 519289a36810SAnil Ravindranath pint_regs->host_ioa_interrupt_clr_reg = 519389a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->host_ioa_intr_clr; 519489a36810SAnil Ravindranath 519589a36810SAnil Ravindranath /* Current version of firmware exposes interrupt mask set 519689a36810SAnil Ravindranath * and mask clr registers through memory mapped bar0. 519789a36810SAnil Ravindranath */ 519889a36810SAnil Ravindranath pinstance->mailbox = mapped_pci_addr + chip_cfg->mailbox; 519989a36810SAnil Ravindranath pinstance->ioa_status = mapped_pci_addr + chip_cfg->ioastatus; 520089a36810SAnil Ravindranath pint_regs->ioa_host_interrupt_mask_reg = 520189a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->ioa_host_mask; 520289a36810SAnil Ravindranath pint_regs->ioa_host_interrupt_mask_clr_reg = 520389a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->ioa_host_mask_clr; 520489a36810SAnil Ravindranath pint_regs->global_interrupt_mask_reg = 520589a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->global_intr_mask; 520689a36810SAnil Ravindranath }; 520789a36810SAnil Ravindranath 520889a36810SAnil Ravindranath pinstance->ioa_reset_attempts = 0; 520989a36810SAnil Ravindranath init_waitqueue_head(&pinstance->reset_wait_q); 521089a36810SAnil Ravindranath 521189a36810SAnil Ravindranath atomic_set(&pinstance->outstanding_cmds, 0); 5212c20c4267SAnil Ravindranath atomic_set(&pinstance->last_message_id, 0); 521389a36810SAnil Ravindranath atomic_set(&pinstance->expose_resources, 0); 521489a36810SAnil Ravindranath 521589a36810SAnil Ravindranath INIT_LIST_HEAD(&pinstance->free_res_q); 521689a36810SAnil Ravindranath INIT_LIST_HEAD(&pinstance->used_res_q); 521789a36810SAnil Ravindranath INIT_LIST_HEAD(&pinstance->free_cmd_pool); 521889a36810SAnil Ravindranath INIT_LIST_HEAD(&pinstance->pending_cmd_pool); 521989a36810SAnil Ravindranath 522089a36810SAnil Ravindranath spin_lock_init(&pinstance->free_pool_lock); 522189a36810SAnil Ravindranath spin_lock_init(&pinstance->pending_pool_lock); 522289a36810SAnil Ravindranath spin_lock_init(&pinstance->resource_lock); 522389a36810SAnil Ravindranath mutex_init(&pinstance->aen_queue_lock); 522489a36810SAnil Ravindranath 522589a36810SAnil Ravindranath /* Work-queue (Shared) for deferred processing error handling */ 522689a36810SAnil Ravindranath INIT_WORK(&pinstance->worker_q, pmcraid_worker_function); 522789a36810SAnil Ravindranath 522889a36810SAnil Ravindranath /* Initialize the default log_level */ 522989a36810SAnil Ravindranath pinstance->current_log_level = pmcraid_log_level; 523089a36810SAnil Ravindranath 523189a36810SAnil Ravindranath /* Setup variables required for reset engine */ 523289a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_UNKNOWN; 523389a36810SAnil Ravindranath pinstance->reset_cmd = NULL; 523489a36810SAnil Ravindranath return 0; 523589a36810SAnil Ravindranath } 523689a36810SAnil Ravindranath 523789a36810SAnil Ravindranath /** 523889a36810SAnil Ravindranath * pmcraid_shutdown - shutdown adapter controller. 523989a36810SAnil Ravindranath * @pdev: pci device struct 524089a36810SAnil Ravindranath * 524189a36810SAnil Ravindranath * Issues an adapter shutdown to the card waits for its completion 524289a36810SAnil Ravindranath * 524389a36810SAnil Ravindranath * Return value 524489a36810SAnil Ravindranath * none 524589a36810SAnil Ravindranath */ 524689a36810SAnil Ravindranath static void pmcraid_shutdown(struct pci_dev *pdev) 524789a36810SAnil Ravindranath { 524889a36810SAnil Ravindranath struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); 524989a36810SAnil Ravindranath pmcraid_reset_bringdown(pinstance); 525089a36810SAnil Ravindranath } 525189a36810SAnil Ravindranath 525289a36810SAnil Ravindranath 525389a36810SAnil Ravindranath /** 525489a36810SAnil Ravindranath * pmcraid_get_minor - returns unused minor number from minor number bitmap 525589a36810SAnil Ravindranath */ 525689a36810SAnil Ravindranath static unsigned short pmcraid_get_minor(void) 525789a36810SAnil Ravindranath { 525889a36810SAnil Ravindranath int minor; 525989a36810SAnil Ravindranath 526089a36810SAnil Ravindranath minor = find_first_zero_bit(pmcraid_minor, sizeof(pmcraid_minor)); 526189a36810SAnil Ravindranath __set_bit(minor, pmcraid_minor); 526289a36810SAnil Ravindranath return minor; 526389a36810SAnil Ravindranath } 526489a36810SAnil Ravindranath 526589a36810SAnil Ravindranath /** 526689a36810SAnil Ravindranath * pmcraid_release_minor - releases given minor back to minor number bitmap 526789a36810SAnil Ravindranath */ 526889a36810SAnil Ravindranath static void pmcraid_release_minor(unsigned short minor) 526989a36810SAnil Ravindranath { 527089a36810SAnil Ravindranath __clear_bit(minor, pmcraid_minor); 527189a36810SAnil Ravindranath } 527289a36810SAnil Ravindranath 527389a36810SAnil Ravindranath /** 527489a36810SAnil Ravindranath * pmcraid_setup_chrdev - allocates a minor number and registers a char device 527589a36810SAnil Ravindranath * 527689a36810SAnil Ravindranath * @pinstance: pointer to adapter instance for which to register device 527789a36810SAnil Ravindranath * 527889a36810SAnil Ravindranath * Return value 527989a36810SAnil Ravindranath * 0 in case of success, otherwise non-zero 528089a36810SAnil Ravindranath */ 528189a36810SAnil Ravindranath static int pmcraid_setup_chrdev(struct pmcraid_instance *pinstance) 528289a36810SAnil Ravindranath { 528389a36810SAnil Ravindranath int minor; 528489a36810SAnil Ravindranath int error; 528589a36810SAnil Ravindranath 528689a36810SAnil Ravindranath minor = pmcraid_get_minor(); 528789a36810SAnil Ravindranath cdev_init(&pinstance->cdev, &pmcraid_fops); 528889a36810SAnil Ravindranath pinstance->cdev.owner = THIS_MODULE; 528989a36810SAnil Ravindranath 529089a36810SAnil Ravindranath error = cdev_add(&pinstance->cdev, MKDEV(pmcraid_major, minor), 1); 529189a36810SAnil Ravindranath 529289a36810SAnil Ravindranath if (error) 529389a36810SAnil Ravindranath pmcraid_release_minor(minor); 529489a36810SAnil Ravindranath else 529589a36810SAnil Ravindranath device_create(pmcraid_class, NULL, MKDEV(pmcraid_major, minor), 5296c20c4267SAnil Ravindranath NULL, "%s%u", PMCRAID_DEVFILE, minor); 529789a36810SAnil Ravindranath return error; 529889a36810SAnil Ravindranath } 529989a36810SAnil Ravindranath 530089a36810SAnil Ravindranath /** 530189a36810SAnil Ravindranath * pmcraid_release_chrdev - unregisters per-adapter management interface 530289a36810SAnil Ravindranath * 530389a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 530489a36810SAnil Ravindranath * 530589a36810SAnil Ravindranath * Return value 530689a36810SAnil Ravindranath * none 530789a36810SAnil Ravindranath */ 530889a36810SAnil Ravindranath static void pmcraid_release_chrdev(struct pmcraid_instance *pinstance) 530989a36810SAnil Ravindranath { 531089a36810SAnil Ravindranath pmcraid_release_minor(MINOR(pinstance->cdev.dev)); 531189a36810SAnil Ravindranath device_destroy(pmcraid_class, 531289a36810SAnil Ravindranath MKDEV(pmcraid_major, MINOR(pinstance->cdev.dev))); 531389a36810SAnil Ravindranath cdev_del(&pinstance->cdev); 531489a36810SAnil Ravindranath } 531589a36810SAnil Ravindranath 531689a36810SAnil Ravindranath /** 531789a36810SAnil Ravindranath * pmcraid_remove - IOA hot plug remove entry point 531889a36810SAnil Ravindranath * @pdev: pci device struct 531989a36810SAnil Ravindranath * 532089a36810SAnil Ravindranath * Return value 532189a36810SAnil Ravindranath * none 532289a36810SAnil Ravindranath */ 53236f039790SGreg Kroah-Hartman static void pmcraid_remove(struct pci_dev *pdev) 532489a36810SAnil Ravindranath { 532589a36810SAnil Ravindranath struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); 532689a36810SAnil Ravindranath 532789a36810SAnil Ravindranath /* remove the management interface (/dev file) for this device */ 532889a36810SAnil Ravindranath pmcraid_release_chrdev(pinstance); 532989a36810SAnil Ravindranath 533089a36810SAnil Ravindranath /* remove host template from scsi midlayer */ 533189a36810SAnil Ravindranath scsi_remove_host(pinstance->host); 533289a36810SAnil Ravindranath 533389a36810SAnil Ravindranath /* block requests from mid-layer */ 533489a36810SAnil Ravindranath scsi_block_requests(pinstance->host); 533589a36810SAnil Ravindranath 533689a36810SAnil Ravindranath /* initiate shutdown adapter */ 533789a36810SAnil Ravindranath pmcraid_shutdown(pdev); 533889a36810SAnil Ravindranath 533989a36810SAnil Ravindranath pmcraid_disable_interrupts(pinstance, ~0); 534043829731STejun Heo flush_work(&pinstance->worker_q); 534189a36810SAnil Ravindranath 534289a36810SAnil Ravindranath pmcraid_kill_tasklets(pinstance); 534389a36810SAnil Ravindranath pmcraid_unregister_interrupt_handler(pinstance); 534489a36810SAnil Ravindranath pmcraid_release_buffers(pinstance); 534589a36810SAnil Ravindranath iounmap(pinstance->mapped_dma_addr); 534689a36810SAnil Ravindranath pci_release_regions(pdev); 534789a36810SAnil Ravindranath scsi_host_put(pinstance->host); 534889a36810SAnil Ravindranath pci_disable_device(pdev); 534989a36810SAnil Ravindranath 535089a36810SAnil Ravindranath return; 535189a36810SAnil Ravindranath } 535289a36810SAnil Ravindranath 535389a36810SAnil Ravindranath #ifdef CONFIG_PM 535489a36810SAnil Ravindranath /** 535589a36810SAnil Ravindranath * pmcraid_suspend - driver suspend entry point for power management 535689a36810SAnil Ravindranath * @pdev: PCI device structure 535789a36810SAnil Ravindranath * @state: PCI power state to suspend routine 535889a36810SAnil Ravindranath * 535989a36810SAnil Ravindranath * Return Value - 0 always 536089a36810SAnil Ravindranath */ 536189a36810SAnil Ravindranath static int pmcraid_suspend(struct pci_dev *pdev, pm_message_t state) 536289a36810SAnil Ravindranath { 536389a36810SAnil Ravindranath struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); 536489a36810SAnil Ravindranath 536589a36810SAnil Ravindranath pmcraid_shutdown(pdev); 536689a36810SAnil Ravindranath pmcraid_disable_interrupts(pinstance, ~0); 536789a36810SAnil Ravindranath pmcraid_kill_tasklets(pinstance); 536889a36810SAnil Ravindranath pci_set_drvdata(pinstance->pdev, pinstance); 536989a36810SAnil Ravindranath pmcraid_unregister_interrupt_handler(pinstance); 537089a36810SAnil Ravindranath pci_save_state(pdev); 537189a36810SAnil Ravindranath pci_disable_device(pdev); 537289a36810SAnil Ravindranath pci_set_power_state(pdev, pci_choose_state(pdev, state)); 537389a36810SAnil Ravindranath 537489a36810SAnil Ravindranath return 0; 537589a36810SAnil Ravindranath } 537689a36810SAnil Ravindranath 537789a36810SAnil Ravindranath /** 537889a36810SAnil Ravindranath * pmcraid_resume - driver resume entry point PCI power management 537989a36810SAnil Ravindranath * @pdev: PCI device structure 538089a36810SAnil Ravindranath * 538189a36810SAnil Ravindranath * Return Value - 0 in case of success. Error code in case of any failure 538289a36810SAnil Ravindranath */ 538389a36810SAnil Ravindranath static int pmcraid_resume(struct pci_dev *pdev) 538489a36810SAnil Ravindranath { 538589a36810SAnil Ravindranath struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); 538689a36810SAnil Ravindranath struct Scsi_Host *host = pinstance->host; 538789a36810SAnil Ravindranath int rc; 538889a36810SAnil Ravindranath 538989a36810SAnil Ravindranath pci_set_power_state(pdev, PCI_D0); 539089a36810SAnil Ravindranath pci_enable_wake(pdev, PCI_D0, 0); 539189a36810SAnil Ravindranath pci_restore_state(pdev); 539289a36810SAnil Ravindranath 539389a36810SAnil Ravindranath rc = pci_enable_device(pdev); 539489a36810SAnil Ravindranath 539589a36810SAnil Ravindranath if (rc) { 539634876402SAnil Ravindranath dev_err(&pdev->dev, "resume: Enable device failed\n"); 539789a36810SAnil Ravindranath return rc; 539889a36810SAnil Ravindranath } 539989a36810SAnil Ravindranath 540089a36810SAnil Ravindranath pci_set_master(pdev); 540189a36810SAnil Ravindranath 540289a36810SAnil Ravindranath if ((sizeof(dma_addr_t) == 4) || 540389a36810SAnil Ravindranath pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) 540489a36810SAnil Ravindranath rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 540589a36810SAnil Ravindranath 540689a36810SAnil Ravindranath if (rc == 0) 540789a36810SAnil Ravindranath rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); 540889a36810SAnil Ravindranath 540989a36810SAnil Ravindranath if (rc != 0) { 541034876402SAnil Ravindranath dev_err(&pdev->dev, "resume: Failed to set PCI DMA mask\n"); 541189a36810SAnil Ravindranath goto disable_device; 541289a36810SAnil Ravindranath } 541389a36810SAnil Ravindranath 5414c20c4267SAnil Ravindranath pmcraid_disable_interrupts(pinstance, ~0); 541589a36810SAnil Ravindranath atomic_set(&pinstance->outstanding_cmds, 0); 541689a36810SAnil Ravindranath rc = pmcraid_register_interrupt_handler(pinstance); 541789a36810SAnil Ravindranath 541889a36810SAnil Ravindranath if (rc) { 541934876402SAnil Ravindranath dev_err(&pdev->dev, 542034876402SAnil Ravindranath "resume: couldn't register interrupt handlers\n"); 542189a36810SAnil Ravindranath rc = -ENODEV; 542289a36810SAnil Ravindranath goto release_host; 542389a36810SAnil Ravindranath } 542489a36810SAnil Ravindranath 542589a36810SAnil Ravindranath pmcraid_init_tasklets(pinstance); 542689a36810SAnil Ravindranath pmcraid_enable_interrupts(pinstance, PMCRAID_PCI_INTERRUPTS); 542789a36810SAnil Ravindranath 542889a36810SAnil Ravindranath /* Start with hard reset sequence which brings up IOA to operational 542989a36810SAnil Ravindranath * state as well as completes the reset sequence. 543089a36810SAnil Ravindranath */ 543189a36810SAnil Ravindranath pinstance->ioa_hard_reset = 1; 543289a36810SAnil Ravindranath 543389a36810SAnil Ravindranath /* Start IOA firmware initialization and bring card to Operational 543489a36810SAnil Ravindranath * state. 543589a36810SAnil Ravindranath */ 543689a36810SAnil Ravindranath if (pmcraid_reset_bringup(pinstance)) { 543734876402SAnil Ravindranath dev_err(&pdev->dev, "couldn't initialize IOA\n"); 543889a36810SAnil Ravindranath rc = -ENODEV; 543989a36810SAnil Ravindranath goto release_tasklets; 544089a36810SAnil Ravindranath } 544189a36810SAnil Ravindranath 544289a36810SAnil Ravindranath return 0; 544389a36810SAnil Ravindranath 544489a36810SAnil Ravindranath release_tasklets: 5445c20c4267SAnil Ravindranath pmcraid_disable_interrupts(pinstance, ~0); 544689a36810SAnil Ravindranath pmcraid_kill_tasklets(pinstance); 544789a36810SAnil Ravindranath pmcraid_unregister_interrupt_handler(pinstance); 544889a36810SAnil Ravindranath 544989a36810SAnil Ravindranath release_host: 545089a36810SAnil Ravindranath scsi_host_put(host); 545189a36810SAnil Ravindranath 545289a36810SAnil Ravindranath disable_device: 545389a36810SAnil Ravindranath pci_disable_device(pdev); 545489a36810SAnil Ravindranath 545589a36810SAnil Ravindranath return rc; 545689a36810SAnil Ravindranath } 545789a36810SAnil Ravindranath 545889a36810SAnil Ravindranath #else 545989a36810SAnil Ravindranath 546089a36810SAnil Ravindranath #define pmcraid_suspend NULL 546189a36810SAnil Ravindranath #define pmcraid_resume NULL 546289a36810SAnil Ravindranath 546389a36810SAnil Ravindranath #endif /* CONFIG_PM */ 546489a36810SAnil Ravindranath 546589a36810SAnil Ravindranath /** 546689a36810SAnil Ravindranath * pmcraid_complete_ioa_reset - Called by either timer or tasklet during 546789a36810SAnil Ravindranath * completion of the ioa reset 546889a36810SAnil Ravindranath * @cmd: pointer to reset command block 546989a36810SAnil Ravindranath */ 547089a36810SAnil Ravindranath static void pmcraid_complete_ioa_reset(struct pmcraid_cmd *cmd) 547189a36810SAnil Ravindranath { 547289a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 547389a36810SAnil Ravindranath unsigned long flags; 547489a36810SAnil Ravindranath 547589a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, flags); 547689a36810SAnil Ravindranath pmcraid_ioa_reset(cmd); 547789a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, flags); 547889a36810SAnil Ravindranath scsi_unblock_requests(pinstance->host); 547989a36810SAnil Ravindranath schedule_work(&pinstance->worker_q); 548089a36810SAnil Ravindranath } 548189a36810SAnil Ravindranath 548289a36810SAnil Ravindranath /** 548389a36810SAnil Ravindranath * pmcraid_set_supported_devs - sends SET SUPPORTED DEVICES to IOAFP 548489a36810SAnil Ravindranath * 548589a36810SAnil Ravindranath * @cmd: pointer to pmcraid_cmd structure 548689a36810SAnil Ravindranath * 548789a36810SAnil Ravindranath * Return Value 548889a36810SAnil Ravindranath * 0 for success or non-zero for failure cases 548989a36810SAnil Ravindranath */ 549089a36810SAnil Ravindranath static void pmcraid_set_supported_devs(struct pmcraid_cmd *cmd) 549189a36810SAnil Ravindranath { 549289a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 549389a36810SAnil Ravindranath void (*cmd_done) (struct pmcraid_cmd *) = pmcraid_complete_ioa_reset; 549489a36810SAnil Ravindranath 549589a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 549689a36810SAnil Ravindranath 549789a36810SAnil Ravindranath ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); 549889a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_IOACMD; 549989a36810SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_SET_SUPPORTED_DEVICES; 550089a36810SAnil Ravindranath ioarcb->cdb[1] = ALL_DEVICES_SUPPORTED; 550189a36810SAnil Ravindranath 550289a36810SAnil Ravindranath /* If this was called as part of resource table reinitialization due to 550389a36810SAnil Ravindranath * lost CCN, it is enough to return the command block back to free pool 550489a36810SAnil Ravindranath * as part of set_supported_devs completion function. 550589a36810SAnil Ravindranath */ 550689a36810SAnil Ravindranath if (cmd->drv_inst->reinit_cfg_table) { 550789a36810SAnil Ravindranath cmd->drv_inst->reinit_cfg_table = 0; 550889a36810SAnil Ravindranath cmd->release = 1; 550989a36810SAnil Ravindranath cmd_done = pmcraid_reinit_cfgtable_done; 551089a36810SAnil Ravindranath } 551189a36810SAnil Ravindranath 551289a36810SAnil Ravindranath /* we will be done with the reset sequence after set supported devices, 551389a36810SAnil Ravindranath * setup the done function to return the command block back to free 551489a36810SAnil Ravindranath * pool 551589a36810SAnil Ravindranath */ 551689a36810SAnil Ravindranath pmcraid_send_cmd(cmd, 551789a36810SAnil Ravindranath cmd_done, 551889a36810SAnil Ravindranath PMCRAID_SET_SUP_DEV_TIMEOUT, 551989a36810SAnil Ravindranath pmcraid_timeout_handler); 552089a36810SAnil Ravindranath return; 552189a36810SAnil Ravindranath } 552289a36810SAnil Ravindranath 552389a36810SAnil Ravindranath /** 5524592488a3SAnil Ravindranath * pmcraid_set_timestamp - set the timestamp to IOAFP 5525592488a3SAnil Ravindranath * 5526592488a3SAnil Ravindranath * @cmd: pointer to pmcraid_cmd structure 5527592488a3SAnil Ravindranath * 5528592488a3SAnil Ravindranath * Return Value 5529592488a3SAnil Ravindranath * 0 for success or non-zero for failure cases 5530592488a3SAnil Ravindranath */ 5531592488a3SAnil Ravindranath static void pmcraid_set_timestamp(struct pmcraid_cmd *cmd) 5532592488a3SAnil Ravindranath { 5533592488a3SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 5534592488a3SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 5535592488a3SAnil Ravindranath __be32 time_stamp_len = cpu_to_be32(PMCRAID_TIMESTAMP_LEN); 5536592488a3SAnil Ravindranath struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; 553745c80be6SArnd Bergmann u64 timestamp; 5538592488a3SAnil Ravindranath 55399c9bd593SAlison Schofield timestamp = ktime_get_real_seconds() * 1000; 5540592488a3SAnil Ravindranath 5541592488a3SAnil Ravindranath pinstance->timestamp_data->timestamp[0] = (__u8)(timestamp); 5542592488a3SAnil Ravindranath pinstance->timestamp_data->timestamp[1] = (__u8)((timestamp) >> 8); 5543592488a3SAnil Ravindranath pinstance->timestamp_data->timestamp[2] = (__u8)((timestamp) >> 16); 5544592488a3SAnil Ravindranath pinstance->timestamp_data->timestamp[3] = (__u8)((timestamp) >> 24); 5545592488a3SAnil Ravindranath pinstance->timestamp_data->timestamp[4] = (__u8)((timestamp) >> 32); 5546592488a3SAnil Ravindranath pinstance->timestamp_data->timestamp[5] = (__u8)((timestamp) >> 40); 5547592488a3SAnil Ravindranath 5548592488a3SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 5549592488a3SAnil Ravindranath ioarcb->request_type = REQ_TYPE_SCSI; 5550592488a3SAnil Ravindranath ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); 5551592488a3SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_SCSI_SET_TIMESTAMP; 5552592488a3SAnil Ravindranath ioarcb->cdb[1] = PMCRAID_SCSI_SERVICE_ACTION; 5553592488a3SAnil Ravindranath memcpy(&(ioarcb->cdb[6]), &time_stamp_len, sizeof(time_stamp_len)); 5554592488a3SAnil Ravindranath 5555592488a3SAnil Ravindranath ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + 5556592488a3SAnil Ravindranath offsetof(struct pmcraid_ioarcb, 5557592488a3SAnil Ravindranath add_data.u.ioadl[0])); 5558592488a3SAnil Ravindranath ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); 555945c80be6SArnd Bergmann ioarcb->ioarcb_bus_addr &= cpu_to_le64(~(0x1FULL)); 5560592488a3SAnil Ravindranath 5561592488a3SAnil Ravindranath ioarcb->request_flags0 |= NO_LINK_DESCS; 5562592488a3SAnil Ravindranath ioarcb->request_flags0 |= TRANSFER_DIR_WRITE; 5563592488a3SAnil Ravindranath ioarcb->data_transfer_length = 5564592488a3SAnil Ravindranath cpu_to_le32(sizeof(struct pmcraid_timestamp_data)); 5565592488a3SAnil Ravindranath ioadl = &(ioarcb->add_data.u.ioadl[0]); 5566592488a3SAnil Ravindranath ioadl->flags = IOADL_FLAGS_LAST_DESC; 5567592488a3SAnil Ravindranath ioadl->address = cpu_to_le64(pinstance->timestamp_data_baddr); 5568592488a3SAnil Ravindranath ioadl->data_len = cpu_to_le32(sizeof(struct pmcraid_timestamp_data)); 5569592488a3SAnil Ravindranath 5570592488a3SAnil Ravindranath if (!pinstance->timestamp_error) { 5571592488a3SAnil Ravindranath pinstance->timestamp_error = 0; 5572592488a3SAnil Ravindranath pmcraid_send_cmd(cmd, pmcraid_set_supported_devs, 5573592488a3SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler); 5574592488a3SAnil Ravindranath } else { 5575592488a3SAnil Ravindranath pmcraid_send_cmd(cmd, pmcraid_return_cmd, 5576592488a3SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler); 5577592488a3SAnil Ravindranath return; 5578592488a3SAnil Ravindranath } 5579592488a3SAnil Ravindranath } 5580592488a3SAnil Ravindranath 5581592488a3SAnil Ravindranath 5582592488a3SAnil Ravindranath /** 558389a36810SAnil Ravindranath * pmcraid_init_res_table - Initialize the resource table 558489a36810SAnil Ravindranath * @cmd: pointer to pmcraid command struct 558589a36810SAnil Ravindranath * 558689a36810SAnil Ravindranath * This function looks through the existing resource table, comparing 558789a36810SAnil Ravindranath * it with the config table. This function will take care of old/new 558889a36810SAnil Ravindranath * devices and schedule adding/removing them from the mid-layer 558989a36810SAnil Ravindranath * as appropriate. 559089a36810SAnil Ravindranath * 559189a36810SAnil Ravindranath * Return value 559289a36810SAnil Ravindranath * None 559389a36810SAnil Ravindranath */ 559489a36810SAnil Ravindranath static void pmcraid_init_res_table(struct pmcraid_cmd *cmd) 559589a36810SAnil Ravindranath { 559689a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 559789a36810SAnil Ravindranath struct pmcraid_resource_entry *res, *temp; 559889a36810SAnil Ravindranath struct pmcraid_config_table_entry *cfgte; 559989a36810SAnil Ravindranath unsigned long lock_flags; 560089a36810SAnil Ravindranath int found, rc, i; 5601c20c4267SAnil Ravindranath u16 fw_version; 560289a36810SAnil Ravindranath LIST_HEAD(old_res); 560389a36810SAnil Ravindranath 560489a36810SAnil Ravindranath if (pinstance->cfg_table->flags & MICROCODE_UPDATE_REQUIRED) 560534876402SAnil Ravindranath pmcraid_err("IOA requires microcode download\n"); 560689a36810SAnil Ravindranath 5607c20c4267SAnil Ravindranath fw_version = be16_to_cpu(pinstance->inq_data->fw_version); 5608c20c4267SAnil Ravindranath 560989a36810SAnil Ravindranath /* resource list is protected by pinstance->resource_lock. 561089a36810SAnil Ravindranath * init_res_table can be called from probe (user-thread) or runtime 561189a36810SAnil Ravindranath * reset (timer/tasklet) 561289a36810SAnil Ravindranath */ 561389a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->resource_lock, lock_flags); 561489a36810SAnil Ravindranath 561589a36810SAnil Ravindranath list_for_each_entry_safe(res, temp, &pinstance->used_res_q, queue) 561689a36810SAnil Ravindranath list_move_tail(&res->queue, &old_res); 561789a36810SAnil Ravindranath 561845c80be6SArnd Bergmann for (i = 0; i < le16_to_cpu(pinstance->cfg_table->num_entries); i++) { 5619c20c4267SAnil Ravindranath if (be16_to_cpu(pinstance->inq_data->fw_version) <= 5620c20c4267SAnil Ravindranath PMCRAID_FW_VERSION_1) 562189a36810SAnil Ravindranath cfgte = &pinstance->cfg_table->entries[i]; 5622c20c4267SAnil Ravindranath else 5623c20c4267SAnil Ravindranath cfgte = (struct pmcraid_config_table_entry *) 5624c20c4267SAnil Ravindranath &pinstance->cfg_table->entries_ext[i]; 562589a36810SAnil Ravindranath 5626c20c4267SAnil Ravindranath if (!pmcraid_expose_resource(fw_version, cfgte)) 562789a36810SAnil Ravindranath continue; 562889a36810SAnil Ravindranath 562989a36810SAnil Ravindranath found = 0; 563089a36810SAnil Ravindranath 563189a36810SAnil Ravindranath /* If this entry was already detected and initialized */ 563289a36810SAnil Ravindranath list_for_each_entry_safe(res, temp, &old_res, queue) { 563389a36810SAnil Ravindranath 563489a36810SAnil Ravindranath rc = memcmp(&res->cfg_entry.resource_address, 563589a36810SAnil Ravindranath &cfgte->resource_address, 563689a36810SAnil Ravindranath sizeof(cfgte->resource_address)); 563789a36810SAnil Ravindranath if (!rc) { 563889a36810SAnil Ravindranath list_move_tail(&res->queue, 563989a36810SAnil Ravindranath &pinstance->used_res_q); 564089a36810SAnil Ravindranath found = 1; 564189a36810SAnil Ravindranath break; 564289a36810SAnil Ravindranath } 564389a36810SAnil Ravindranath } 564489a36810SAnil Ravindranath 564589a36810SAnil Ravindranath /* If this is new entry, initialize it and add it the queue */ 564689a36810SAnil Ravindranath if (!found) { 564789a36810SAnil Ravindranath 564889a36810SAnil Ravindranath if (list_empty(&pinstance->free_res_q)) { 564934876402SAnil Ravindranath pmcraid_err("Too many devices attached\n"); 565089a36810SAnil Ravindranath break; 565189a36810SAnil Ravindranath } 565289a36810SAnil Ravindranath 565389a36810SAnil Ravindranath found = 1; 565489a36810SAnil Ravindranath res = list_entry(pinstance->free_res_q.next, 565589a36810SAnil Ravindranath struct pmcraid_resource_entry, queue); 565689a36810SAnil Ravindranath 565789a36810SAnil Ravindranath res->scsi_dev = NULL; 565889a36810SAnil Ravindranath res->change_detected = RES_CHANGE_ADD; 565989a36810SAnil Ravindranath res->reset_progress = 0; 566089a36810SAnil Ravindranath list_move_tail(&res->queue, &pinstance->used_res_q); 566189a36810SAnil Ravindranath } 566289a36810SAnil Ravindranath 566389a36810SAnil Ravindranath /* copy new configuration table entry details into driver 566489a36810SAnil Ravindranath * maintained resource entry 566589a36810SAnil Ravindranath */ 566689a36810SAnil Ravindranath if (found) { 566789a36810SAnil Ravindranath memcpy(&res->cfg_entry, cfgte, 5668c20c4267SAnil Ravindranath pinstance->config_table_entry_size); 566989a36810SAnil Ravindranath pmcraid_info("New res type:%x, vset:%x, addr:%x:\n", 567089a36810SAnil Ravindranath res->cfg_entry.resource_type, 5671c20c4267SAnil Ravindranath (fw_version <= PMCRAID_FW_VERSION_1 ? 5672c20c4267SAnil Ravindranath res->cfg_entry.unique_flags1 : 567345c80be6SArnd Bergmann le16_to_cpu(res->cfg_entry.array_id) & 0xFF), 567489a36810SAnil Ravindranath le32_to_cpu(res->cfg_entry.resource_address)); 567589a36810SAnil Ravindranath } 567689a36810SAnil Ravindranath } 567789a36810SAnil Ravindranath 567889a36810SAnil Ravindranath /* Detect any deleted entries, mark them for deletion from mid-layer */ 567989a36810SAnil Ravindranath list_for_each_entry_safe(res, temp, &old_res, queue) { 568089a36810SAnil Ravindranath 568189a36810SAnil Ravindranath if (res->scsi_dev) { 568289a36810SAnil Ravindranath res->change_detected = RES_CHANGE_DEL; 568389a36810SAnil Ravindranath res->cfg_entry.resource_handle = 568489a36810SAnil Ravindranath PMCRAID_INVALID_RES_HANDLE; 568589a36810SAnil Ravindranath list_move_tail(&res->queue, &pinstance->used_res_q); 568689a36810SAnil Ravindranath } else { 568789a36810SAnil Ravindranath list_move_tail(&res->queue, &pinstance->free_res_q); 568889a36810SAnil Ravindranath } 568989a36810SAnil Ravindranath } 569089a36810SAnil Ravindranath 569189a36810SAnil Ravindranath /* release the resource list lock */ 569289a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); 5693592488a3SAnil Ravindranath pmcraid_set_timestamp(cmd); 569489a36810SAnil Ravindranath } 569589a36810SAnil Ravindranath 569689a36810SAnil Ravindranath /** 569789a36810SAnil Ravindranath * pmcraid_querycfg - Send a Query IOA Config to the adapter. 569889a36810SAnil Ravindranath * @cmd: pointer pmcraid_cmd struct 569989a36810SAnil Ravindranath * 570089a36810SAnil Ravindranath * This function sends a Query IOA Configuration command to the adapter to 570189a36810SAnil Ravindranath * retrieve the IOA configuration table. 570289a36810SAnil Ravindranath * 570389a36810SAnil Ravindranath * Return value: 570489a36810SAnil Ravindranath * none 570589a36810SAnil Ravindranath */ 570689a36810SAnil Ravindranath static void pmcraid_querycfg(struct pmcraid_cmd *cmd) 570789a36810SAnil Ravindranath { 570889a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 570989a36810SAnil Ravindranath struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; 571089a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 571145c80be6SArnd Bergmann __be32 cfg_table_size = cpu_to_be32(sizeof(struct pmcraid_config_table)); 571289a36810SAnil Ravindranath 5713c20c4267SAnil Ravindranath if (be16_to_cpu(pinstance->inq_data->fw_version) <= 5714c20c4267SAnil Ravindranath PMCRAID_FW_VERSION_1) 5715c20c4267SAnil Ravindranath pinstance->config_table_entry_size = 5716c20c4267SAnil Ravindranath sizeof(struct pmcraid_config_table_entry); 5717c20c4267SAnil Ravindranath else 5718c20c4267SAnil Ravindranath pinstance->config_table_entry_size = 5719c20c4267SAnil Ravindranath sizeof(struct pmcraid_config_table_entry_ext); 5720c20c4267SAnil Ravindranath 572189a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_IOACMD; 572289a36810SAnil Ravindranath ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); 572389a36810SAnil Ravindranath 572489a36810SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_QUERY_IOA_CONFIG; 572589a36810SAnil Ravindranath 572689a36810SAnil Ravindranath /* firmware requires 4-byte length field, specified in B.E format */ 572789a36810SAnil Ravindranath memcpy(&(ioarcb->cdb[10]), &cfg_table_size, sizeof(cfg_table_size)); 572889a36810SAnil Ravindranath 572989a36810SAnil Ravindranath /* Since entire config table can be described by single IOADL, it can 573089a36810SAnil Ravindranath * be part of IOARCB itself 573189a36810SAnil Ravindranath */ 573289a36810SAnil Ravindranath ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + 573389a36810SAnil Ravindranath offsetof(struct pmcraid_ioarcb, 573489a36810SAnil Ravindranath add_data.u.ioadl[0])); 573589a36810SAnil Ravindranath ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); 573645c80be6SArnd Bergmann ioarcb->ioarcb_bus_addr &= cpu_to_le64(~0x1FULL); 573789a36810SAnil Ravindranath 573889a36810SAnil Ravindranath ioarcb->request_flags0 |= NO_LINK_DESCS; 573989a36810SAnil Ravindranath ioarcb->data_transfer_length = 574089a36810SAnil Ravindranath cpu_to_le32(sizeof(struct pmcraid_config_table)); 574189a36810SAnil Ravindranath 574289a36810SAnil Ravindranath ioadl = &(ioarcb->add_data.u.ioadl[0]); 574388197966SAnil Ravindranath ioadl->flags = IOADL_FLAGS_LAST_DESC; 574489a36810SAnil Ravindranath ioadl->address = cpu_to_le64(pinstance->cfg_table_bus_addr); 574589a36810SAnil Ravindranath ioadl->data_len = cpu_to_le32(sizeof(struct pmcraid_config_table)); 574689a36810SAnil Ravindranath 574789a36810SAnil Ravindranath pmcraid_send_cmd(cmd, pmcraid_init_res_table, 574889a36810SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler); 574989a36810SAnil Ravindranath } 575089a36810SAnil Ravindranath 575189a36810SAnil Ravindranath 575289a36810SAnil Ravindranath /** 5753c20c4267SAnil Ravindranath * pmcraid_probe - PCI probe entry pointer for PMC MaxRAID controller driver 575489a36810SAnil Ravindranath * @pdev: pointer to pci device structure 575589a36810SAnil Ravindranath * @dev_id: pointer to device ids structure 575689a36810SAnil Ravindranath * 575789a36810SAnil Ravindranath * Return Value 575889a36810SAnil Ravindranath * returns 0 if the device is claimed and successfully configured. 575989a36810SAnil Ravindranath * returns non-zero error code in case of any failure 576089a36810SAnil Ravindranath */ 57616f039790SGreg Kroah-Hartman static int pmcraid_probe(struct pci_dev *pdev, 57626f039790SGreg Kroah-Hartman const struct pci_device_id *dev_id) 576389a36810SAnil Ravindranath { 576489a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 576589a36810SAnil Ravindranath struct Scsi_Host *host; 576689a36810SAnil Ravindranath void __iomem *mapped_pci_addr; 576789a36810SAnil Ravindranath int rc = PCIBIOS_SUCCESSFUL; 576889a36810SAnil Ravindranath 576989a36810SAnil Ravindranath if (atomic_read(&pmcraid_adapter_count) >= PMCRAID_MAX_ADAPTERS) { 577089a36810SAnil Ravindranath pmcraid_err 577189a36810SAnil Ravindranath ("maximum number(%d) of supported adapters reached\n", 577289a36810SAnil Ravindranath atomic_read(&pmcraid_adapter_count)); 577389a36810SAnil Ravindranath return -ENOMEM; 577489a36810SAnil Ravindranath } 577589a36810SAnil Ravindranath 577689a36810SAnil Ravindranath atomic_inc(&pmcraid_adapter_count); 577789a36810SAnil Ravindranath rc = pci_enable_device(pdev); 577889a36810SAnil Ravindranath 577989a36810SAnil Ravindranath if (rc) { 578089a36810SAnil Ravindranath dev_err(&pdev->dev, "Cannot enable adapter\n"); 578189a36810SAnil Ravindranath atomic_dec(&pmcraid_adapter_count); 578289a36810SAnil Ravindranath return rc; 578389a36810SAnil Ravindranath } 578489a36810SAnil Ravindranath 578589a36810SAnil Ravindranath dev_info(&pdev->dev, 578689a36810SAnil Ravindranath "Found new IOA(%x:%x), Total IOA count: %d\n", 578789a36810SAnil Ravindranath pdev->vendor, pdev->device, 578889a36810SAnil Ravindranath atomic_read(&pmcraid_adapter_count)); 578989a36810SAnil Ravindranath 579089a36810SAnil Ravindranath rc = pci_request_regions(pdev, PMCRAID_DRIVER_NAME); 579189a36810SAnil Ravindranath 579289a36810SAnil Ravindranath if (rc < 0) { 579389a36810SAnil Ravindranath dev_err(&pdev->dev, 579489a36810SAnil Ravindranath "Couldn't register memory range of registers\n"); 579589a36810SAnil Ravindranath goto out_disable_device; 579689a36810SAnil Ravindranath } 579789a36810SAnil Ravindranath 579889a36810SAnil Ravindranath mapped_pci_addr = pci_iomap(pdev, 0, 0); 579989a36810SAnil Ravindranath 580089a36810SAnil Ravindranath if (!mapped_pci_addr) { 580189a36810SAnil Ravindranath dev_err(&pdev->dev, "Couldn't map PCI registers memory\n"); 580289a36810SAnil Ravindranath rc = -ENOMEM; 580389a36810SAnil Ravindranath goto out_release_regions; 580489a36810SAnil Ravindranath } 580589a36810SAnil Ravindranath 580689a36810SAnil Ravindranath pci_set_master(pdev); 580789a36810SAnil Ravindranath 580889a36810SAnil Ravindranath /* Firmware requires the system bus address of IOARCB to be within 580989a36810SAnil Ravindranath * 32-bit addressable range though it has 64-bit IOARRIN register. 581089a36810SAnil Ravindranath * However, firmware supports 64-bit streaming DMA buffers, whereas 581189a36810SAnil Ravindranath * coherent buffers are to be 32-bit. Since pci_alloc_consistent always 581289a36810SAnil Ravindranath * returns memory within 4GB (if not, change this logic), coherent 581325985edcSLucas De Marchi * buffers are within firmware acceptable address ranges. 581489a36810SAnil Ravindranath */ 581589a36810SAnil Ravindranath if ((sizeof(dma_addr_t) == 4) || 581689a36810SAnil Ravindranath pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) 581789a36810SAnil Ravindranath rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 581889a36810SAnil Ravindranath 581989a36810SAnil Ravindranath /* firmware expects 32-bit DMA addresses for IOARRIN register; set 32 582089a36810SAnil Ravindranath * bit mask for pci_alloc_consistent to return addresses within 4GB 582189a36810SAnil Ravindranath */ 582289a36810SAnil Ravindranath if (rc == 0) 582389a36810SAnil Ravindranath rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); 582489a36810SAnil Ravindranath 582589a36810SAnil Ravindranath if (rc != 0) { 582689a36810SAnil Ravindranath dev_err(&pdev->dev, "Failed to set PCI DMA mask\n"); 582789a36810SAnil Ravindranath goto cleanup_nomem; 582889a36810SAnil Ravindranath } 582989a36810SAnil Ravindranath 583089a36810SAnil Ravindranath host = scsi_host_alloc(&pmcraid_host_template, 583189a36810SAnil Ravindranath sizeof(struct pmcraid_instance)); 583289a36810SAnil Ravindranath 583389a36810SAnil Ravindranath if (!host) { 583489a36810SAnil Ravindranath dev_err(&pdev->dev, "scsi_host_alloc failed!\n"); 583589a36810SAnil Ravindranath rc = -ENOMEM; 583689a36810SAnil Ravindranath goto cleanup_nomem; 583789a36810SAnil Ravindranath } 583889a36810SAnil Ravindranath 583989a36810SAnil Ravindranath host->max_id = PMCRAID_MAX_NUM_TARGETS_PER_BUS; 584089a36810SAnil Ravindranath host->max_lun = PMCRAID_MAX_NUM_LUNS_PER_TARGET; 584189a36810SAnil Ravindranath host->unique_id = host->host_no; 584289a36810SAnil Ravindranath host->max_channel = PMCRAID_MAX_BUS_TO_SCAN; 584389a36810SAnil Ravindranath host->max_cmd_len = PMCRAID_MAX_CDB_LEN; 584489a36810SAnil Ravindranath 584589a36810SAnil Ravindranath /* zero out entire instance structure */ 584689a36810SAnil Ravindranath pinstance = (struct pmcraid_instance *)host->hostdata; 584789a36810SAnil Ravindranath memset(pinstance, 0, sizeof(*pinstance)); 584889a36810SAnil Ravindranath 584989a36810SAnil Ravindranath pinstance->chip_cfg = 585089a36810SAnil Ravindranath (struct pmcraid_chip_details *)(dev_id->driver_data); 585189a36810SAnil Ravindranath 585289a36810SAnil Ravindranath rc = pmcraid_init_instance(pdev, host, mapped_pci_addr); 585389a36810SAnil Ravindranath 585489a36810SAnil Ravindranath if (rc < 0) { 585589a36810SAnil Ravindranath dev_err(&pdev->dev, "failed to initialize adapter instance\n"); 585689a36810SAnil Ravindranath goto out_scsi_host_put; 585789a36810SAnil Ravindranath } 585889a36810SAnil Ravindranath 585989a36810SAnil Ravindranath pci_set_drvdata(pdev, pinstance); 586089a36810SAnil Ravindranath 586189a36810SAnil Ravindranath /* Save PCI config-space for use following the reset */ 586289a36810SAnil Ravindranath rc = pci_save_state(pinstance->pdev); 586389a36810SAnil Ravindranath 586489a36810SAnil Ravindranath if (rc != 0) { 586589a36810SAnil Ravindranath dev_err(&pdev->dev, "Failed to save PCI config space\n"); 586689a36810SAnil Ravindranath goto out_scsi_host_put; 586789a36810SAnil Ravindranath } 586889a36810SAnil Ravindranath 586989a36810SAnil Ravindranath pmcraid_disable_interrupts(pinstance, ~0); 587089a36810SAnil Ravindranath 587189a36810SAnil Ravindranath rc = pmcraid_register_interrupt_handler(pinstance); 587289a36810SAnil Ravindranath 587389a36810SAnil Ravindranath if (rc) { 587434876402SAnil Ravindranath dev_err(&pdev->dev, "couldn't register interrupt handler\n"); 587589a36810SAnil Ravindranath goto out_scsi_host_put; 587689a36810SAnil Ravindranath } 587789a36810SAnil Ravindranath 587889a36810SAnil Ravindranath pmcraid_init_tasklets(pinstance); 587989a36810SAnil Ravindranath 588089a36810SAnil Ravindranath /* allocate verious buffers used by LLD.*/ 588189a36810SAnil Ravindranath rc = pmcraid_init_buffers(pinstance); 588289a36810SAnil Ravindranath 588389a36810SAnil Ravindranath if (rc) { 588489a36810SAnil Ravindranath pmcraid_err("couldn't allocate memory blocks\n"); 588589a36810SAnil Ravindranath goto out_unregister_isr; 588689a36810SAnil Ravindranath } 588789a36810SAnil Ravindranath 588889a36810SAnil Ravindranath /* check the reset type required */ 588989a36810SAnil Ravindranath pmcraid_reset_type(pinstance); 589089a36810SAnil Ravindranath 589189a36810SAnil Ravindranath pmcraid_enable_interrupts(pinstance, PMCRAID_PCI_INTERRUPTS); 589289a36810SAnil Ravindranath 589389a36810SAnil Ravindranath /* Start IOA firmware initialization and bring card to Operational 589489a36810SAnil Ravindranath * state. 589589a36810SAnil Ravindranath */ 589689a36810SAnil Ravindranath pmcraid_info("starting IOA initialization sequence\n"); 589789a36810SAnil Ravindranath if (pmcraid_reset_bringup(pinstance)) { 589834876402SAnil Ravindranath dev_err(&pdev->dev, "couldn't initialize IOA\n"); 589989a36810SAnil Ravindranath rc = 1; 590089a36810SAnil Ravindranath goto out_release_bufs; 590189a36810SAnil Ravindranath } 590289a36810SAnil Ravindranath 590389a36810SAnil Ravindranath /* Add adapter instance into mid-layer list */ 590489a36810SAnil Ravindranath rc = scsi_add_host(pinstance->host, &pdev->dev); 590589a36810SAnil Ravindranath if (rc != 0) { 590689a36810SAnil Ravindranath pmcraid_err("couldn't add host into mid-layer: %d\n", rc); 590789a36810SAnil Ravindranath goto out_release_bufs; 590889a36810SAnil Ravindranath } 590989a36810SAnil Ravindranath 591089a36810SAnil Ravindranath scsi_scan_host(pinstance->host); 591189a36810SAnil Ravindranath 591289a36810SAnil Ravindranath rc = pmcraid_setup_chrdev(pinstance); 591389a36810SAnil Ravindranath 591489a36810SAnil Ravindranath if (rc != 0) { 591589a36810SAnil Ravindranath pmcraid_err("couldn't create mgmt interface, error: %x\n", 591689a36810SAnil Ravindranath rc); 591789a36810SAnil Ravindranath goto out_remove_host; 591889a36810SAnil Ravindranath } 591989a36810SAnil Ravindranath 592089a36810SAnil Ravindranath /* Schedule worker thread to handle CCN and take care of adding and 592189a36810SAnil Ravindranath * removing devices to OS 592289a36810SAnil Ravindranath */ 592389a36810SAnil Ravindranath atomic_set(&pinstance->expose_resources, 1); 592489a36810SAnil Ravindranath schedule_work(&pinstance->worker_q); 592589a36810SAnil Ravindranath return rc; 592689a36810SAnil Ravindranath 592789a36810SAnil Ravindranath out_remove_host: 592889a36810SAnil Ravindranath scsi_remove_host(host); 592989a36810SAnil Ravindranath 593089a36810SAnil Ravindranath out_release_bufs: 593189a36810SAnil Ravindranath pmcraid_release_buffers(pinstance); 593289a36810SAnil Ravindranath 593389a36810SAnil Ravindranath out_unregister_isr: 593489a36810SAnil Ravindranath pmcraid_kill_tasklets(pinstance); 593589a36810SAnil Ravindranath pmcraid_unregister_interrupt_handler(pinstance); 593689a36810SAnil Ravindranath 593789a36810SAnil Ravindranath out_scsi_host_put: 593889a36810SAnil Ravindranath scsi_host_put(host); 593989a36810SAnil Ravindranath 594089a36810SAnil Ravindranath cleanup_nomem: 594189a36810SAnil Ravindranath iounmap(mapped_pci_addr); 594289a36810SAnil Ravindranath 594389a36810SAnil Ravindranath out_release_regions: 594489a36810SAnil Ravindranath pci_release_regions(pdev); 594589a36810SAnil Ravindranath 594689a36810SAnil Ravindranath out_disable_device: 594789a36810SAnil Ravindranath atomic_dec(&pmcraid_adapter_count); 594889a36810SAnil Ravindranath pci_disable_device(pdev); 594989a36810SAnil Ravindranath return -ENODEV; 595089a36810SAnil Ravindranath } 595189a36810SAnil Ravindranath 595289a36810SAnil Ravindranath /* 595389a36810SAnil Ravindranath * PCI driver structure of pcmraid driver 595489a36810SAnil Ravindranath */ 595589a36810SAnil Ravindranath static struct pci_driver pmcraid_driver = { 595689a36810SAnil Ravindranath .name = PMCRAID_DRIVER_NAME, 595789a36810SAnil Ravindranath .id_table = pmcraid_pci_table, 595889a36810SAnil Ravindranath .probe = pmcraid_probe, 595989a36810SAnil Ravindranath .remove = pmcraid_remove, 596089a36810SAnil Ravindranath .suspend = pmcraid_suspend, 596189a36810SAnil Ravindranath .resume = pmcraid_resume, 596289a36810SAnil Ravindranath .shutdown = pmcraid_shutdown 596389a36810SAnil Ravindranath }; 596489a36810SAnil Ravindranath 596589a36810SAnil Ravindranath /** 596689a36810SAnil Ravindranath * pmcraid_init - module load entry point 596789a36810SAnil Ravindranath */ 596889a36810SAnil Ravindranath static int __init pmcraid_init(void) 596989a36810SAnil Ravindranath { 597089a36810SAnil Ravindranath dev_t dev; 597189a36810SAnil Ravindranath int error; 597289a36810SAnil Ravindranath 5973a1b66665SMichal Marek pmcraid_info("%s Device Driver version: %s\n", 5974a1b66665SMichal Marek PMCRAID_DRIVER_NAME, PMCRAID_DRIVER_VERSION); 597589a36810SAnil Ravindranath 597689a36810SAnil Ravindranath error = alloc_chrdev_region(&dev, 0, 597789a36810SAnil Ravindranath PMCRAID_MAX_ADAPTERS, 597889a36810SAnil Ravindranath PMCRAID_DEVFILE); 597989a36810SAnil Ravindranath 598089a36810SAnil Ravindranath if (error) { 598189a36810SAnil Ravindranath pmcraid_err("failed to get a major number for adapters\n"); 598289a36810SAnil Ravindranath goto out_init; 598389a36810SAnil Ravindranath } 598489a36810SAnil Ravindranath 598589a36810SAnil Ravindranath pmcraid_major = MAJOR(dev); 598689a36810SAnil Ravindranath pmcraid_class = class_create(THIS_MODULE, PMCRAID_DEVFILE); 598789a36810SAnil Ravindranath 598889a36810SAnil Ravindranath if (IS_ERR(pmcraid_class)) { 598989a36810SAnil Ravindranath error = PTR_ERR(pmcraid_class); 5990278cee05SMasanari Iida pmcraid_err("failed to register with sysfs, error = %x\n", 599189a36810SAnil Ravindranath error); 599289a36810SAnil Ravindranath goto out_unreg_chrdev; 599389a36810SAnil Ravindranath } 599489a36810SAnil Ravindranath 599589a36810SAnil Ravindranath error = pmcraid_netlink_init(); 599689a36810SAnil Ravindranath 59972d76a247SQuentin Lambert if (error) { 59982d76a247SQuentin Lambert class_destroy(pmcraid_class); 599989a36810SAnil Ravindranath goto out_unreg_chrdev; 60002d76a247SQuentin Lambert } 600189a36810SAnil Ravindranath 600289a36810SAnil Ravindranath error = pci_register_driver(&pmcraid_driver); 600389a36810SAnil Ravindranath 600489a36810SAnil Ravindranath if (error == 0) 600589a36810SAnil Ravindranath goto out_init; 600689a36810SAnil Ravindranath 600789a36810SAnil Ravindranath pmcraid_err("failed to register pmcraid driver, error = %x\n", 600889a36810SAnil Ravindranath error); 600989a36810SAnil Ravindranath class_destroy(pmcraid_class); 601089a36810SAnil Ravindranath pmcraid_netlink_release(); 601189a36810SAnil Ravindranath 601289a36810SAnil Ravindranath out_unreg_chrdev: 601389a36810SAnil Ravindranath unregister_chrdev_region(MKDEV(pmcraid_major, 0), PMCRAID_MAX_ADAPTERS); 601434876402SAnil Ravindranath 601589a36810SAnil Ravindranath out_init: 601689a36810SAnil Ravindranath return error; 601789a36810SAnil Ravindranath } 601889a36810SAnil Ravindranath 601989a36810SAnil Ravindranath /** 602089a36810SAnil Ravindranath * pmcraid_exit - module unload entry point 602189a36810SAnil Ravindranath */ 602289a36810SAnil Ravindranath static void __exit pmcraid_exit(void) 602389a36810SAnil Ravindranath { 602489a36810SAnil Ravindranath pmcraid_netlink_release(); 602589a36810SAnil Ravindranath unregister_chrdev_region(MKDEV(pmcraid_major, 0), 602689a36810SAnil Ravindranath PMCRAID_MAX_ADAPTERS); 602789a36810SAnil Ravindranath pci_unregister_driver(&pmcraid_driver); 6028592488a3SAnil Ravindranath class_destroy(pmcraid_class); 602989a36810SAnil Ravindranath } 603089a36810SAnil Ravindranath 603189a36810SAnil Ravindranath module_init(pmcraid_init); 603289a36810SAnil Ravindranath module_exit(pmcraid_exit); 6033