11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 289a36810SAnil Ravindranath /* 389a36810SAnil Ravindranath * pmcraid.c -- driver for PMC Sierra MaxRAID controller adapters 489a36810SAnil Ravindranath * 5729c8456SAnil Ravindranath * Written By: Anil Ravindranath<anil_ravindranath@pmc-sierra.com> 6729c8456SAnil Ravindranath * PMC-Sierra Inc 789a36810SAnil Ravindranath * 889a36810SAnil Ravindranath * Copyright (C) 2008, 2009 PMC Sierra Inc 989a36810SAnil Ravindranath */ 1089a36810SAnil Ravindranath #include <linux/fs.h> 1189a36810SAnil Ravindranath #include <linux/init.h> 1289a36810SAnil Ravindranath #include <linux/types.h> 1389a36810SAnil Ravindranath #include <linux/errno.h> 1489a36810SAnil Ravindranath #include <linux/kernel.h> 1589a36810SAnil Ravindranath #include <linux/ioport.h> 1689a36810SAnil Ravindranath #include <linux/delay.h> 1789a36810SAnil Ravindranath #include <linux/pci.h> 1889a36810SAnil Ravindranath #include <linux/wait.h> 1989a36810SAnil Ravindranath #include <linux/spinlock.h> 2089a36810SAnil Ravindranath #include <linux/sched.h> 2189a36810SAnil Ravindranath #include <linux/interrupt.h> 2289a36810SAnil Ravindranath #include <linux/blkdev.h> 2389a36810SAnil Ravindranath #include <linux/firmware.h> 2489a36810SAnil Ravindranath #include <linux/module.h> 2589a36810SAnil Ravindranath #include <linux/moduleparam.h> 2689a36810SAnil Ravindranath #include <linux/hdreg.h> 2789a36810SAnil Ravindranath #include <linux/io.h> 285a0e3ad6STejun Heo #include <linux/slab.h> 2989a36810SAnil Ravindranath #include <asm/irq.h> 3089a36810SAnil Ravindranath #include <asm/processor.h> 3189a36810SAnil Ravindranath #include <linux/libata.h> 3289a36810SAnil Ravindranath #include <linux/mutex.h> 339c9bd593SAlison Schofield #include <linux/ktime.h> 3489a36810SAnil Ravindranath #include <scsi/scsi.h> 3589a36810SAnil Ravindranath #include <scsi/scsi_host.h> 3634876402SAnil Ravindranath #include <scsi/scsi_device.h> 3789a36810SAnil Ravindranath #include <scsi/scsi_tcq.h> 3889a36810SAnil Ravindranath #include <scsi/scsi_eh.h> 3989a36810SAnil Ravindranath #include <scsi/scsi_cmnd.h> 4089a36810SAnil Ravindranath #include <scsi/scsicam.h> 4189a36810SAnil Ravindranath 4289a36810SAnil Ravindranath #include "pmcraid.h" 4389a36810SAnil Ravindranath 4489a36810SAnil Ravindranath /* 4589a36810SAnil Ravindranath * Module configuration parameters 4689a36810SAnil Ravindranath */ 4789a36810SAnil Ravindranath static unsigned int pmcraid_debug_log; 4889a36810SAnil Ravindranath static unsigned int pmcraid_disable_aen; 4989a36810SAnil Ravindranath static unsigned int pmcraid_log_level = IOASC_LOG_LEVEL_MUST; 505da61410SAnil Ravindranath static unsigned int pmcraid_enable_msix; 5189a36810SAnil Ravindranath 5289a36810SAnil Ravindranath /* 5389a36810SAnil Ravindranath * Data structures to support multiple adapters by the LLD. 5489a36810SAnil Ravindranath * pmcraid_adapter_count - count of configured adapters 5589a36810SAnil Ravindranath */ 5689a36810SAnil Ravindranath static atomic_t pmcraid_adapter_count = ATOMIC_INIT(0); 5789a36810SAnil Ravindranath 5889a36810SAnil Ravindranath /* 5989a36810SAnil Ravindranath * Supporting user-level control interface through IOCTL commands. 6089a36810SAnil Ravindranath * pmcraid_major - major number to use 6189a36810SAnil Ravindranath * pmcraid_minor - minor number(s) to use 6289a36810SAnil Ravindranath */ 6389a36810SAnil Ravindranath static unsigned int pmcraid_major; 6489a36810SAnil Ravindranath static struct class *pmcraid_class; 65144b139cSArnd Bergmann static DECLARE_BITMAP(pmcraid_minor, PMCRAID_MAX_ADAPTERS); 6689a36810SAnil Ravindranath 6789a36810SAnil Ravindranath /* 6889a36810SAnil Ravindranath * Module parameters 6989a36810SAnil Ravindranath */ 70729c8456SAnil Ravindranath MODULE_AUTHOR("Anil Ravindranath<anil_ravindranath@pmc-sierra.com>"); 7189a36810SAnil Ravindranath MODULE_DESCRIPTION("PMC Sierra MaxRAID Controller Driver"); 7289a36810SAnil Ravindranath MODULE_LICENSE("GPL"); 7389a36810SAnil Ravindranath MODULE_VERSION(PMCRAID_DRIVER_VERSION); 7489a36810SAnil Ravindranath 7589a36810SAnil Ravindranath module_param_named(log_level, pmcraid_log_level, uint, (S_IRUGO | S_IWUSR)); 7689a36810SAnil Ravindranath MODULE_PARM_DESC(log_level, 7789a36810SAnil Ravindranath "Enables firmware error code logging, default :1 high-severity" 7889a36810SAnil Ravindranath " errors, 2: all errors including high-severity errors," 7989a36810SAnil Ravindranath " 0: disables logging"); 8089a36810SAnil Ravindranath 8189a36810SAnil Ravindranath module_param_named(debug, pmcraid_debug_log, uint, (S_IRUGO | S_IWUSR)); 8289a36810SAnil Ravindranath MODULE_PARM_DESC(debug, 8389a36810SAnil Ravindranath "Enable driver verbose message logging. Set 1 to enable." 8489a36810SAnil Ravindranath "(default: 0)"); 8589a36810SAnil Ravindranath 8689a36810SAnil Ravindranath module_param_named(disable_aen, pmcraid_disable_aen, uint, (S_IRUGO | S_IWUSR)); 8789a36810SAnil Ravindranath MODULE_PARM_DESC(disable_aen, 8889a36810SAnil Ravindranath "Disable driver aen notifications to apps. Set 1 to disable." 8989a36810SAnil Ravindranath "(default: 0)"); 9089a36810SAnil Ravindranath 9189a36810SAnil Ravindranath /* chip specific constants for PMC MaxRAID controllers (same for 9289a36810SAnil Ravindranath * 0x5220 and 0x8010 9389a36810SAnil Ravindranath */ 9489a36810SAnil Ravindranath static struct pmcraid_chip_details pmcraid_chip_cfg[] = { 9589a36810SAnil Ravindranath { 9689a36810SAnil Ravindranath .ioastatus = 0x0, 9789a36810SAnil Ravindranath .ioarrin = 0x00040, 9889a36810SAnil Ravindranath .mailbox = 0x7FC30, 9989a36810SAnil Ravindranath .global_intr_mask = 0x00034, 10089a36810SAnil Ravindranath .ioa_host_intr = 0x0009C, 10189a36810SAnil Ravindranath .ioa_host_intr_clr = 0x000A0, 102c20c4267SAnil Ravindranath .ioa_host_msix_intr = 0x7FC40, 10389a36810SAnil Ravindranath .ioa_host_mask = 0x7FC28, 10489a36810SAnil Ravindranath .ioa_host_mask_clr = 0x7FC28, 10589a36810SAnil Ravindranath .host_ioa_intr = 0x00020, 10689a36810SAnil Ravindranath .host_ioa_intr_clr = 0x00020, 10789a36810SAnil Ravindranath .transop_timeout = 300 10889a36810SAnil Ravindranath } 10989a36810SAnil Ravindranath }; 11089a36810SAnil Ravindranath 11189a36810SAnil Ravindranath /* 11289a36810SAnil Ravindranath * PCI device ids supported by pmcraid driver 11389a36810SAnil Ravindranath */ 1146f039790SGreg Kroah-Hartman static struct pci_device_id pmcraid_pci_table[] = { 11589a36810SAnil Ravindranath { PCI_DEVICE(PCI_VENDOR_ID_PMC, PCI_DEVICE_ID_PMC_MAXRAID), 11689a36810SAnil Ravindranath 0, 0, (kernel_ulong_t)&pmcraid_chip_cfg[0] 11789a36810SAnil Ravindranath }, 11889a36810SAnil Ravindranath {} 11989a36810SAnil Ravindranath }; 12089a36810SAnil Ravindranath 12189a36810SAnil Ravindranath MODULE_DEVICE_TABLE(pci, pmcraid_pci_table); 12289a36810SAnil Ravindranath 12389a36810SAnil Ravindranath 12489a36810SAnil Ravindranath 12589a36810SAnil Ravindranath /** 12689a36810SAnil Ravindranath * pmcraid_slave_alloc - Prepare for commands to a device 12789a36810SAnil Ravindranath * @scsi_dev: scsi device struct 12889a36810SAnil Ravindranath * 12989a36810SAnil Ravindranath * This function is called by mid-layer prior to sending any command to the new 13089a36810SAnil Ravindranath * device. Stores resource entry details of the device in scsi_device struct. 13189a36810SAnil Ravindranath * Queuecommand uses the resource handle and other details to fill up IOARCB 13289a36810SAnil Ravindranath * while sending commands to the device. 13389a36810SAnil Ravindranath * 13489a36810SAnil Ravindranath * Return value: 13589a36810SAnil Ravindranath * 0 on success / -ENXIO if device does not exist 13689a36810SAnil Ravindranath */ 13789a36810SAnil Ravindranath static int pmcraid_slave_alloc(struct scsi_device *scsi_dev) 13889a36810SAnil Ravindranath { 13989a36810SAnil Ravindranath struct pmcraid_resource_entry *temp, *res = NULL; 14089a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 14189a36810SAnil Ravindranath u8 target, bus, lun; 14289a36810SAnil Ravindranath unsigned long lock_flags; 14389a36810SAnil Ravindranath int rc = -ENXIO; 144c20c4267SAnil Ravindranath u16 fw_version; 145c20c4267SAnil Ravindranath 14689a36810SAnil Ravindranath pinstance = shost_priv(scsi_dev->host); 14789a36810SAnil Ravindranath 148c20c4267SAnil Ravindranath fw_version = be16_to_cpu(pinstance->inq_data->fw_version); 149c20c4267SAnil Ravindranath 15089a36810SAnil Ravindranath /* Driver exposes VSET and GSCSI resources only; all other device types 15189a36810SAnil Ravindranath * are not exposed. Resource list is synchronized using resource lock 15289a36810SAnil Ravindranath * so any traversal or modifications to the list should be done inside 15389a36810SAnil Ravindranath * this lock 15489a36810SAnil Ravindranath */ 15589a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->resource_lock, lock_flags); 15689a36810SAnil Ravindranath list_for_each_entry(temp, &pinstance->used_res_q, queue) { 15789a36810SAnil Ravindranath 158729c8456SAnil Ravindranath /* do not expose VSETs with order-ids > MAX_VSET_TARGETS */ 15989a36810SAnil Ravindranath if (RES_IS_VSET(temp->cfg_entry)) { 160c20c4267SAnil Ravindranath if (fw_version <= PMCRAID_FW_VERSION_1) 16189a36810SAnil Ravindranath target = temp->cfg_entry.unique_flags1; 162c20c4267SAnil Ravindranath else 16345c80be6SArnd Bergmann target = le16_to_cpu(temp->cfg_entry.array_id) & 0xFF; 164c20c4267SAnil Ravindranath 165729c8456SAnil Ravindranath if (target > PMCRAID_MAX_VSET_TARGETS) 16689a36810SAnil Ravindranath continue; 16789a36810SAnil Ravindranath bus = PMCRAID_VSET_BUS_ID; 16889a36810SAnil Ravindranath lun = 0; 16989a36810SAnil Ravindranath } else if (RES_IS_GSCSI(temp->cfg_entry)) { 17089a36810SAnil Ravindranath target = RES_TARGET(temp->cfg_entry.resource_address); 17189a36810SAnil Ravindranath bus = PMCRAID_PHYS_BUS_ID; 17289a36810SAnil Ravindranath lun = RES_LUN(temp->cfg_entry.resource_address); 17389a36810SAnil Ravindranath } else { 17489a36810SAnil Ravindranath continue; 17589a36810SAnil Ravindranath } 17689a36810SAnil Ravindranath 17789a36810SAnil Ravindranath if (bus == scsi_dev->channel && 17889a36810SAnil Ravindranath target == scsi_dev->id && 17989a36810SAnil Ravindranath lun == scsi_dev->lun) { 18089a36810SAnil Ravindranath res = temp; 18189a36810SAnil Ravindranath break; 18289a36810SAnil Ravindranath } 18389a36810SAnil Ravindranath } 18489a36810SAnil Ravindranath 18589a36810SAnil Ravindranath if (res) { 18689a36810SAnil Ravindranath res->scsi_dev = scsi_dev; 18789a36810SAnil Ravindranath scsi_dev->hostdata = res; 18889a36810SAnil Ravindranath res->change_detected = 0; 18989a36810SAnil Ravindranath atomic_set(&res->read_failures, 0); 19089a36810SAnil Ravindranath atomic_set(&res->write_failures, 0); 19189a36810SAnil Ravindranath rc = 0; 19289a36810SAnil Ravindranath } 19389a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); 19489a36810SAnil Ravindranath return rc; 19589a36810SAnil Ravindranath } 19689a36810SAnil Ravindranath 19789a36810SAnil Ravindranath /** 19889a36810SAnil Ravindranath * pmcraid_slave_configure - Configures a SCSI device 19989a36810SAnil Ravindranath * @scsi_dev: scsi device struct 20089a36810SAnil Ravindranath * 20125985edcSLucas De Marchi * This function is executed by SCSI mid layer just after a device is first 20289a36810SAnil Ravindranath * scanned (i.e. it has responded to an INQUIRY). For VSET resources, the 20389a36810SAnil Ravindranath * timeout value (default 30s) will be over-written to a higher value (60s) 20489a36810SAnil Ravindranath * and max_sectors value will be over-written to 512. It also sets queue depth 20589a36810SAnil Ravindranath * to host->cmd_per_lun value 20689a36810SAnil Ravindranath * 20789a36810SAnil Ravindranath * Return value: 20889a36810SAnil Ravindranath * 0 on success 20989a36810SAnil Ravindranath */ 21089a36810SAnil Ravindranath static int pmcraid_slave_configure(struct scsi_device *scsi_dev) 21189a36810SAnil Ravindranath { 21289a36810SAnil Ravindranath struct pmcraid_resource_entry *res = scsi_dev->hostdata; 21389a36810SAnil Ravindranath 21489a36810SAnil Ravindranath if (!res) 21589a36810SAnil Ravindranath return 0; 21689a36810SAnil Ravindranath 21789a36810SAnil Ravindranath /* LLD exposes VSETs and Enclosure devices only */ 21889a36810SAnil Ravindranath if (RES_IS_GSCSI(res->cfg_entry) && 21989a36810SAnil Ravindranath scsi_dev->type != TYPE_ENCLOSURE) 22089a36810SAnil Ravindranath return -ENXIO; 22189a36810SAnil Ravindranath 22289a36810SAnil Ravindranath pmcraid_info("configuring %x:%x:%x:%x\n", 22389a36810SAnil Ravindranath scsi_dev->host->unique_id, 22489a36810SAnil Ravindranath scsi_dev->channel, 22589a36810SAnil Ravindranath scsi_dev->id, 2269cb78c16SHannes Reinecke (u8)scsi_dev->lun); 22789a36810SAnil Ravindranath 22889a36810SAnil Ravindranath if (RES_IS_GSCSI(res->cfg_entry)) { 22989a36810SAnil Ravindranath scsi_dev->allow_restart = 1; 23089a36810SAnil Ravindranath } else if (RES_IS_VSET(res->cfg_entry)) { 23189a36810SAnil Ravindranath scsi_dev->allow_restart = 1; 23289a36810SAnil Ravindranath blk_queue_rq_timeout(scsi_dev->request_queue, 23389a36810SAnil Ravindranath PMCRAID_VSET_IO_TIMEOUT); 234086fa5ffSMartin K. Petersen blk_queue_max_hw_sectors(scsi_dev->request_queue, 23589a36810SAnil Ravindranath PMCRAID_VSET_MAX_SECTORS); 23689a36810SAnil Ravindranath } 23789a36810SAnil Ravindranath 238c8b09f6fSChristoph Hellwig /* 239c8b09f6fSChristoph Hellwig * We never want to report TCQ support for these types of devices. 240c8b09f6fSChristoph Hellwig */ 241c8b09f6fSChristoph Hellwig if (!RES_IS_GSCSI(res->cfg_entry) && !RES_IS_VSET(res->cfg_entry)) 242c8b09f6fSChristoph Hellwig scsi_dev->tagged_supported = 0; 24389a36810SAnil Ravindranath 24489a36810SAnil Ravindranath return 0; 24589a36810SAnil Ravindranath } 24689a36810SAnil Ravindranath 24789a36810SAnil Ravindranath /** 24889a36810SAnil Ravindranath * pmcraid_slave_destroy - Unconfigure a SCSI device before removing it 24989a36810SAnil Ravindranath * 25089a36810SAnil Ravindranath * @scsi_dev: scsi device struct 25189a36810SAnil Ravindranath * 25289a36810SAnil Ravindranath * This is called by mid-layer before removing a device. Pointer assignments 25389a36810SAnil Ravindranath * done in pmcraid_slave_alloc will be reset to NULL here. 25489a36810SAnil Ravindranath * 25589a36810SAnil Ravindranath * Return value 25689a36810SAnil Ravindranath * none 25789a36810SAnil Ravindranath */ 25889a36810SAnil Ravindranath static void pmcraid_slave_destroy(struct scsi_device *scsi_dev) 25989a36810SAnil Ravindranath { 26089a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 26189a36810SAnil Ravindranath 26289a36810SAnil Ravindranath res = (struct pmcraid_resource_entry *)scsi_dev->hostdata; 26389a36810SAnil Ravindranath 26489a36810SAnil Ravindranath if (res) 26589a36810SAnil Ravindranath res->scsi_dev = NULL; 26689a36810SAnil Ravindranath 26789a36810SAnil Ravindranath scsi_dev->hostdata = NULL; 26889a36810SAnil Ravindranath } 26989a36810SAnil Ravindranath 27089a36810SAnil Ravindranath /** 27189a36810SAnil Ravindranath * pmcraid_change_queue_depth - Change the device's queue depth 27289a36810SAnil Ravindranath * @scsi_dev: scsi device struct 27389a36810SAnil Ravindranath * @depth: depth to set 27489a36810SAnil Ravindranath * 27589a36810SAnil Ravindranath * Return value 27689a36810SAnil Ravindranath * actual depth set 27789a36810SAnil Ravindranath */ 278db5ed4dfSChristoph Hellwig static int pmcraid_change_queue_depth(struct scsi_device *scsi_dev, int depth) 27989a36810SAnil Ravindranath { 28089a36810SAnil Ravindranath if (depth > PMCRAID_MAX_CMD_PER_LUN) 28189a36810SAnil Ravindranath depth = PMCRAID_MAX_CMD_PER_LUN; 282db5ed4dfSChristoph Hellwig return scsi_change_queue_depth(scsi_dev, depth); 28389a36810SAnil Ravindranath } 28489a36810SAnil Ravindranath 28589a36810SAnil Ravindranath /** 28689a36810SAnil Ravindranath * pmcraid_init_cmdblk - initializes a command block 28789a36810SAnil Ravindranath * 28889a36810SAnil Ravindranath * @cmd: pointer to struct pmcraid_cmd to be initialized 28989a36810SAnil Ravindranath * @index: if >=0 first time initialization; otherwise reinitialization 29089a36810SAnil Ravindranath * 29189a36810SAnil Ravindranath * Return Value 29289a36810SAnil Ravindranath * None 29389a36810SAnil Ravindranath */ 29461b96d5bSBaoyou Xie static void pmcraid_init_cmdblk(struct pmcraid_cmd *cmd, int index) 29589a36810SAnil Ravindranath { 29689a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &(cmd->ioa_cb->ioarcb); 29789a36810SAnil Ravindranath dma_addr_t dma_addr = cmd->ioa_cb_bus_addr; 29889a36810SAnil Ravindranath 29989a36810SAnil Ravindranath if (index >= 0) { 30089a36810SAnil Ravindranath /* first time initialization (called from probe) */ 30189a36810SAnil Ravindranath u32 ioasa_offset = 30289a36810SAnil Ravindranath offsetof(struct pmcraid_control_block, ioasa); 30389a36810SAnil Ravindranath 30489a36810SAnil Ravindranath cmd->index = index; 30589a36810SAnil Ravindranath ioarcb->response_handle = cpu_to_le32(index << 2); 30689a36810SAnil Ravindranath ioarcb->ioarcb_bus_addr = cpu_to_le64(dma_addr); 30789a36810SAnil Ravindranath ioarcb->ioasa_bus_addr = cpu_to_le64(dma_addr + ioasa_offset); 30889a36810SAnil Ravindranath ioarcb->ioasa_len = cpu_to_le16(sizeof(struct pmcraid_ioasa)); 30989a36810SAnil Ravindranath } else { 31089a36810SAnil Ravindranath /* re-initialization of various lengths, called once command is 31189a36810SAnil Ravindranath * processed by IOA 31289a36810SAnil Ravindranath */ 31389a36810SAnil Ravindranath memset(&cmd->ioa_cb->ioarcb.cdb, 0, PMCRAID_MAX_CDB_LEN); 314c20c4267SAnil Ravindranath ioarcb->hrrq_id = 0; 31589a36810SAnil Ravindranath ioarcb->request_flags0 = 0; 31689a36810SAnil Ravindranath ioarcb->request_flags1 = 0; 31789a36810SAnil Ravindranath ioarcb->cmd_timeout = 0; 31845c80be6SArnd Bergmann ioarcb->ioarcb_bus_addr &= cpu_to_le64(~0x1FULL); 31989a36810SAnil Ravindranath ioarcb->ioadl_bus_addr = 0; 32089a36810SAnil Ravindranath ioarcb->ioadl_length = 0; 32189a36810SAnil Ravindranath ioarcb->data_transfer_length = 0; 32289a36810SAnil Ravindranath ioarcb->add_cmd_param_length = 0; 32389a36810SAnil Ravindranath ioarcb->add_cmd_param_offset = 0; 32489a36810SAnil Ravindranath cmd->ioa_cb->ioasa.ioasc = 0; 32589a36810SAnil Ravindranath cmd->ioa_cb->ioasa.residual_data_length = 0; 326c20c4267SAnil Ravindranath cmd->time_left = 0; 32789a36810SAnil Ravindranath } 32889a36810SAnil Ravindranath 32989a36810SAnil Ravindranath cmd->cmd_done = NULL; 33089a36810SAnil Ravindranath cmd->scsi_cmd = NULL; 33189a36810SAnil Ravindranath cmd->release = 0; 33289a36810SAnil Ravindranath cmd->completion_req = 0; 333144b139cSArnd Bergmann cmd->sense_buffer = NULL; 334c20c4267SAnil Ravindranath cmd->sense_buffer_dma = 0; 33589a36810SAnil Ravindranath cmd->dma_handle = 0; 336242b5657SKees Cook timer_setup(&cmd->timer, NULL, 0); 33789a36810SAnil Ravindranath } 33889a36810SAnil Ravindranath 33989a36810SAnil Ravindranath /** 34089a36810SAnil Ravindranath * pmcraid_reinit_cmdblk - reinitialize a command block 34189a36810SAnil Ravindranath * 34289a36810SAnil Ravindranath * @cmd: pointer to struct pmcraid_cmd to be reinitialized 34389a36810SAnil Ravindranath * 34489a36810SAnil Ravindranath * Return Value 34589a36810SAnil Ravindranath * None 34689a36810SAnil Ravindranath */ 34789a36810SAnil Ravindranath static void pmcraid_reinit_cmdblk(struct pmcraid_cmd *cmd) 34889a36810SAnil Ravindranath { 34989a36810SAnil Ravindranath pmcraid_init_cmdblk(cmd, -1); 35089a36810SAnil Ravindranath } 35189a36810SAnil Ravindranath 35289a36810SAnil Ravindranath /** 35389a36810SAnil Ravindranath * pmcraid_get_free_cmd - get a free cmd block from command block pool 35489a36810SAnil Ravindranath * @pinstance: adapter instance structure 35589a36810SAnil Ravindranath * 35689a36810SAnil Ravindranath * Return Value: 35789a36810SAnil Ravindranath * returns pointer to cmd block or NULL if no blocks are available 35889a36810SAnil Ravindranath */ 35989a36810SAnil Ravindranath static struct pmcraid_cmd *pmcraid_get_free_cmd( 36089a36810SAnil Ravindranath struct pmcraid_instance *pinstance 36189a36810SAnil Ravindranath ) 36289a36810SAnil Ravindranath { 36389a36810SAnil Ravindranath struct pmcraid_cmd *cmd = NULL; 36489a36810SAnil Ravindranath unsigned long lock_flags; 36589a36810SAnil Ravindranath 36689a36810SAnil Ravindranath /* free cmd block list is protected by free_pool_lock */ 36789a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->free_pool_lock, lock_flags); 36889a36810SAnil Ravindranath 36989a36810SAnil Ravindranath if (!list_empty(&pinstance->free_cmd_pool)) { 37089a36810SAnil Ravindranath cmd = list_entry(pinstance->free_cmd_pool.next, 37189a36810SAnil Ravindranath struct pmcraid_cmd, free_list); 37289a36810SAnil Ravindranath list_del(&cmd->free_list); 37389a36810SAnil Ravindranath } 37489a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->free_pool_lock, lock_flags); 37589a36810SAnil Ravindranath 37689a36810SAnil Ravindranath /* Initialize the command block before giving it the caller */ 37789a36810SAnil Ravindranath if (cmd != NULL) 37889a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 37989a36810SAnil Ravindranath return cmd; 38089a36810SAnil Ravindranath } 38189a36810SAnil Ravindranath 38289a36810SAnil Ravindranath /** 38389a36810SAnil Ravindranath * pmcraid_return_cmd - return a completed command block back into free pool 38489a36810SAnil Ravindranath * @cmd: pointer to the command block 38589a36810SAnil Ravindranath * 38689a36810SAnil Ravindranath * Return Value: 38789a36810SAnil Ravindranath * nothing 38889a36810SAnil Ravindranath */ 38961b96d5bSBaoyou Xie static void pmcraid_return_cmd(struct pmcraid_cmd *cmd) 39089a36810SAnil Ravindranath { 39189a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 39289a36810SAnil Ravindranath unsigned long lock_flags; 39389a36810SAnil Ravindranath 39489a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->free_pool_lock, lock_flags); 39589a36810SAnil Ravindranath list_add_tail(&cmd->free_list, &pinstance->free_cmd_pool); 39689a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->free_pool_lock, lock_flags); 39789a36810SAnil Ravindranath } 39889a36810SAnil Ravindranath 39989a36810SAnil Ravindranath /** 40089a36810SAnil Ravindranath * pmcraid_read_interrupts - reads IOA interrupts 40189a36810SAnil Ravindranath * 40289a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 40389a36810SAnil Ravindranath * 40489a36810SAnil Ravindranath * Return value 40589a36810SAnil Ravindranath * interrupts read from IOA 40689a36810SAnil Ravindranath */ 40789a36810SAnil Ravindranath static u32 pmcraid_read_interrupts(struct pmcraid_instance *pinstance) 40889a36810SAnil Ravindranath { 409c20c4267SAnil Ravindranath return (pinstance->interrupt_mode) ? 410c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.ioa_host_msix_interrupt_reg) : 411c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.ioa_host_interrupt_reg); 41289a36810SAnil Ravindranath } 41389a36810SAnil Ravindranath 41489a36810SAnil Ravindranath /** 41589a36810SAnil Ravindranath * pmcraid_disable_interrupts - Masks and clears all specified interrupts 41689a36810SAnil Ravindranath * 41789a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 41889a36810SAnil Ravindranath * @intrs: interrupts to disable 41989a36810SAnil Ravindranath * 42089a36810SAnil Ravindranath * Return Value 42189a36810SAnil Ravindranath * None 42289a36810SAnil Ravindranath */ 42389a36810SAnil Ravindranath static void pmcraid_disable_interrupts( 42489a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 42589a36810SAnil Ravindranath u32 intrs 42689a36810SAnil Ravindranath ) 42789a36810SAnil Ravindranath { 42889a36810SAnil Ravindranath u32 gmask = ioread32(pinstance->int_regs.global_interrupt_mask_reg); 42989a36810SAnil Ravindranath u32 nmask = gmask | GLOBAL_INTERRUPT_MASK; 43089a36810SAnil Ravindranath 43189a36810SAnil Ravindranath iowrite32(intrs, pinstance->int_regs.ioa_host_interrupt_clr_reg); 432c20c4267SAnil Ravindranath iowrite32(nmask, pinstance->int_regs.global_interrupt_mask_reg); 433c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.global_interrupt_mask_reg); 434c20c4267SAnil Ravindranath 435c20c4267SAnil Ravindranath if (!pinstance->interrupt_mode) { 436c20c4267SAnil Ravindranath iowrite32(intrs, 437c20c4267SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_mask_reg); 43889a36810SAnil Ravindranath ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg); 43989a36810SAnil Ravindranath } 440c20c4267SAnil Ravindranath } 44189a36810SAnil Ravindranath 44289a36810SAnil Ravindranath /** 44389a36810SAnil Ravindranath * pmcraid_enable_interrupts - Enables specified interrupts 44489a36810SAnil Ravindranath * 44589a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 4463673b7b0SLee Jones * @intrs: interrupts to enable 44789a36810SAnil Ravindranath * 44889a36810SAnil Ravindranath * Return Value 44989a36810SAnil Ravindranath * None 45089a36810SAnil Ravindranath */ 45189a36810SAnil Ravindranath static void pmcraid_enable_interrupts( 45289a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 4533673b7b0SLee Jones u32 intrs) 45489a36810SAnil Ravindranath { 45589a36810SAnil Ravindranath u32 gmask = ioread32(pinstance->int_regs.global_interrupt_mask_reg); 45689a36810SAnil Ravindranath u32 nmask = gmask & (~GLOBAL_INTERRUPT_MASK); 45789a36810SAnil Ravindranath 45889a36810SAnil Ravindranath iowrite32(nmask, pinstance->int_regs.global_interrupt_mask_reg); 459c20c4267SAnil Ravindranath 460c20c4267SAnil Ravindranath if (!pinstance->interrupt_mode) { 461c20c4267SAnil Ravindranath iowrite32(~intrs, 462c20c4267SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_mask_reg); 46389a36810SAnil Ravindranath ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg); 464c20c4267SAnil Ravindranath } 46589a36810SAnil Ravindranath 46689a36810SAnil Ravindranath pmcraid_info("enabled interrupts global mask = %x intr_mask = %x\n", 46789a36810SAnil Ravindranath ioread32(pinstance->int_regs.global_interrupt_mask_reg), 46889a36810SAnil Ravindranath ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg)); 46989a36810SAnil Ravindranath } 47089a36810SAnil Ravindranath 47189a36810SAnil Ravindranath /** 472c20c4267SAnil Ravindranath * pmcraid_clr_trans_op - clear trans to op interrupt 473c20c4267SAnil Ravindranath * 474c20c4267SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 475c20c4267SAnil Ravindranath * 476c20c4267SAnil Ravindranath * Return Value 477c20c4267SAnil Ravindranath * None 478c20c4267SAnil Ravindranath */ 479c20c4267SAnil Ravindranath static void pmcraid_clr_trans_op( 480c20c4267SAnil Ravindranath struct pmcraid_instance *pinstance 481c20c4267SAnil Ravindranath ) 482c20c4267SAnil Ravindranath { 483c20c4267SAnil Ravindranath unsigned long lock_flags; 484c20c4267SAnil Ravindranath 485c20c4267SAnil Ravindranath if (!pinstance->interrupt_mode) { 486c20c4267SAnil Ravindranath iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, 487c20c4267SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_mask_reg); 488c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg); 489c20c4267SAnil Ravindranath iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, 490c20c4267SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_clr_reg); 491c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.ioa_host_interrupt_clr_reg); 492c20c4267SAnil Ravindranath } 493c20c4267SAnil Ravindranath 494c20c4267SAnil Ravindranath if (pinstance->reset_cmd != NULL) { 495c20c4267SAnil Ravindranath del_timer(&pinstance->reset_cmd->timer); 496c20c4267SAnil Ravindranath spin_lock_irqsave( 497c20c4267SAnil Ravindranath pinstance->host->host_lock, lock_flags); 498c20c4267SAnil Ravindranath pinstance->reset_cmd->cmd_done(pinstance->reset_cmd); 499c20c4267SAnil Ravindranath spin_unlock_irqrestore( 500c20c4267SAnil Ravindranath pinstance->host->host_lock, lock_flags); 501c20c4267SAnil Ravindranath } 502c20c4267SAnil Ravindranath } 503c20c4267SAnil Ravindranath 504c20c4267SAnil Ravindranath /** 50589a36810SAnil Ravindranath * pmcraid_reset_type - Determine the required reset type 50689a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 50789a36810SAnil Ravindranath * 50889a36810SAnil Ravindranath * IOA requires hard reset if any of the following conditions is true. 50989a36810SAnil Ravindranath * 1. If HRRQ valid interrupt is not masked 51089a36810SAnil Ravindranath * 2. IOA reset alert doorbell is set 51189a36810SAnil Ravindranath * 3. If there are any error interrupts 51289a36810SAnil Ravindranath */ 51389a36810SAnil Ravindranath static void pmcraid_reset_type(struct pmcraid_instance *pinstance) 51489a36810SAnil Ravindranath { 51589a36810SAnil Ravindranath u32 mask; 51689a36810SAnil Ravindranath u32 intrs; 51789a36810SAnil Ravindranath u32 alerts; 51889a36810SAnil Ravindranath 51989a36810SAnil Ravindranath mask = ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg); 52089a36810SAnil Ravindranath intrs = ioread32(pinstance->int_regs.ioa_host_interrupt_reg); 52189a36810SAnil Ravindranath alerts = ioread32(pinstance->int_regs.host_ioa_interrupt_reg); 52289a36810SAnil Ravindranath 52389a36810SAnil Ravindranath if ((mask & INTRS_HRRQ_VALID) == 0 || 52489a36810SAnil Ravindranath (alerts & DOORBELL_IOA_RESET_ALERT) || 52589a36810SAnil Ravindranath (intrs & PMCRAID_ERROR_INTERRUPTS)) { 52689a36810SAnil Ravindranath pmcraid_info("IOA requires hard reset\n"); 52789a36810SAnil Ravindranath pinstance->ioa_hard_reset = 1; 52889a36810SAnil Ravindranath } 52989a36810SAnil Ravindranath 53089a36810SAnil Ravindranath /* If unit check is active, trigger the dump */ 53189a36810SAnil Ravindranath if (intrs & INTRS_IOA_UNIT_CHECK) 53289a36810SAnil Ravindranath pinstance->ioa_unit_check = 1; 53389a36810SAnil Ravindranath } 53489a36810SAnil Ravindranath 5353673b7b0SLee Jones static void pmcraid_ioa_reset(struct pmcraid_cmd *); 53689a36810SAnil Ravindranath /** 53789a36810SAnil Ravindranath * pmcraid_bist_done - completion function for PCI BIST 5383673b7b0SLee Jones * @t: pointer to reset command 53989a36810SAnil Ravindranath * Return Value 54089a36810SAnil Ravindranath * none 54189a36810SAnil Ravindranath */ 542242b5657SKees Cook static void pmcraid_bist_done(struct timer_list *t) 54389a36810SAnil Ravindranath { 544242b5657SKees Cook struct pmcraid_cmd *cmd = from_timer(cmd, t, timer); 54589a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 54689a36810SAnil Ravindranath unsigned long lock_flags; 54789a36810SAnil Ravindranath int rc; 54889a36810SAnil Ravindranath u16 pci_reg; 54989a36810SAnil Ravindranath 55089a36810SAnil Ravindranath rc = pci_read_config_word(pinstance->pdev, PCI_COMMAND, &pci_reg); 55189a36810SAnil Ravindranath 55289a36810SAnil Ravindranath /* If PCI config space can't be accessed wait for another two secs */ 55389a36810SAnil Ravindranath if ((rc != PCIBIOS_SUCCESSFUL || (!(pci_reg & PCI_COMMAND_MEMORY))) && 554c20c4267SAnil Ravindranath cmd->time_left > 0) { 55589a36810SAnil Ravindranath pmcraid_info("BIST not complete, waiting another 2 secs\n"); 556c20c4267SAnil Ravindranath cmd->timer.expires = jiffies + cmd->time_left; 557c20c4267SAnil Ravindranath cmd->time_left = 0; 55889a36810SAnil Ravindranath add_timer(&cmd->timer); 55989a36810SAnil Ravindranath } else { 560c20c4267SAnil Ravindranath cmd->time_left = 0; 56189a36810SAnil Ravindranath pmcraid_info("BIST is complete, proceeding with reset\n"); 56289a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 56389a36810SAnil Ravindranath pmcraid_ioa_reset(cmd); 56489a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 56589a36810SAnil Ravindranath } 56689a36810SAnil Ravindranath } 56789a36810SAnil Ravindranath 56889a36810SAnil Ravindranath /** 56989a36810SAnil Ravindranath * pmcraid_start_bist - starts BIST 57089a36810SAnil Ravindranath * @cmd: pointer to reset cmd 57189a36810SAnil Ravindranath * Return Value 57289a36810SAnil Ravindranath * none 57389a36810SAnil Ravindranath */ 57489a36810SAnil Ravindranath static void pmcraid_start_bist(struct pmcraid_cmd *cmd) 57589a36810SAnil Ravindranath { 57689a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 57789a36810SAnil Ravindranath u32 doorbells, intrs; 57889a36810SAnil Ravindranath 57989a36810SAnil Ravindranath /* proceed with bist and wait for 2 seconds */ 58089a36810SAnil Ravindranath iowrite32(DOORBELL_IOA_START_BIST, 58189a36810SAnil Ravindranath pinstance->int_regs.host_ioa_interrupt_reg); 58289a36810SAnil Ravindranath doorbells = ioread32(pinstance->int_regs.host_ioa_interrupt_reg); 58389a36810SAnil Ravindranath intrs = ioread32(pinstance->int_regs.ioa_host_interrupt_reg); 58489a36810SAnil Ravindranath pmcraid_info("doorbells after start bist: %x intrs: %x\n", 58589a36810SAnil Ravindranath doorbells, intrs); 58689a36810SAnil Ravindranath 587c20c4267SAnil Ravindranath cmd->time_left = msecs_to_jiffies(PMCRAID_BIST_TIMEOUT); 58889a36810SAnil Ravindranath cmd->timer.expires = jiffies + msecs_to_jiffies(PMCRAID_BIST_TIMEOUT); 589841b86f3SKees Cook cmd->timer.function = pmcraid_bist_done; 59089a36810SAnil Ravindranath add_timer(&cmd->timer); 59189a36810SAnil Ravindranath } 59289a36810SAnil Ravindranath 59389a36810SAnil Ravindranath /** 59489a36810SAnil Ravindranath * pmcraid_reset_alert_done - completion routine for reset_alert 5953673b7b0SLee Jones * @t: pointer to command block used in reset sequence 59689a36810SAnil Ravindranath * Return value 59789a36810SAnil Ravindranath * None 59889a36810SAnil Ravindranath */ 599242b5657SKees Cook static void pmcraid_reset_alert_done(struct timer_list *t) 60089a36810SAnil Ravindranath { 601242b5657SKees Cook struct pmcraid_cmd *cmd = from_timer(cmd, t, timer); 60289a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 60389a36810SAnil Ravindranath u32 status = ioread32(pinstance->ioa_status); 60489a36810SAnil Ravindranath unsigned long lock_flags; 60589a36810SAnil Ravindranath 60689a36810SAnil Ravindranath /* if the critical operation in progress bit is set or the wait times 60789a36810SAnil Ravindranath * out, invoke reset engine to proceed with hard reset. If there is 60889a36810SAnil Ravindranath * some more time to wait, restart the timer 60989a36810SAnil Ravindranath */ 61089a36810SAnil Ravindranath if (((status & INTRS_CRITICAL_OP_IN_PROGRESS) == 0) || 611c20c4267SAnil Ravindranath cmd->time_left <= 0) { 61289a36810SAnil Ravindranath pmcraid_info("critical op is reset proceeding with reset\n"); 61389a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 61489a36810SAnil Ravindranath pmcraid_ioa_reset(cmd); 61589a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 61689a36810SAnil Ravindranath } else { 61789a36810SAnil Ravindranath pmcraid_info("critical op is not yet reset waiting again\n"); 61889a36810SAnil Ravindranath /* restart timer if some more time is available to wait */ 619c20c4267SAnil Ravindranath cmd->time_left -= PMCRAID_CHECK_FOR_RESET_TIMEOUT; 62089a36810SAnil Ravindranath cmd->timer.expires = jiffies + PMCRAID_CHECK_FOR_RESET_TIMEOUT; 621841b86f3SKees Cook cmd->timer.function = pmcraid_reset_alert_done; 62289a36810SAnil Ravindranath add_timer(&cmd->timer); 62389a36810SAnil Ravindranath } 62489a36810SAnil Ravindranath } 62589a36810SAnil Ravindranath 6263673b7b0SLee Jones static void pmcraid_notify_ioastate(struct pmcraid_instance *, u32); 62789a36810SAnil Ravindranath /** 62889a36810SAnil Ravindranath * pmcraid_reset_alert - alerts IOA for a possible reset 62989a36810SAnil Ravindranath * @cmd: command block to be used for reset sequence. 63089a36810SAnil Ravindranath * 63189a36810SAnil Ravindranath * Return Value 63289a36810SAnil Ravindranath * returns 0 if pci config-space is accessible and RESET_DOORBELL is 63389a36810SAnil Ravindranath * successfully written to IOA. Returns non-zero in case pci_config_space 63489a36810SAnil Ravindranath * is not accessible 63589a36810SAnil Ravindranath */ 63689a36810SAnil Ravindranath static void pmcraid_reset_alert(struct pmcraid_cmd *cmd) 63789a36810SAnil Ravindranath { 63889a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 63989a36810SAnil Ravindranath u32 doorbells; 64089a36810SAnil Ravindranath int rc; 64189a36810SAnil Ravindranath u16 pci_reg; 64289a36810SAnil Ravindranath 64389a36810SAnil Ravindranath /* If we are able to access IOA PCI config space, alert IOA that we are 64489a36810SAnil Ravindranath * going to reset it soon. This enables IOA to preserv persistent error 64589a36810SAnil Ravindranath * data if any. In case memory space is not accessible, proceed with 64689a36810SAnil Ravindranath * BIST or slot_reset 64789a36810SAnil Ravindranath */ 64889a36810SAnil Ravindranath rc = pci_read_config_word(pinstance->pdev, PCI_COMMAND, &pci_reg); 64989a36810SAnil Ravindranath if ((rc == PCIBIOS_SUCCESSFUL) && (pci_reg & PCI_COMMAND_MEMORY)) { 65089a36810SAnil Ravindranath 65189a36810SAnil Ravindranath /* wait for IOA permission i.e until CRITICAL_OPERATION bit is 65289a36810SAnil Ravindranath * reset IOA doesn't generate any interrupts when CRITICAL 65389a36810SAnil Ravindranath * OPERATION bit is reset. A timer is started to wait for this 65489a36810SAnil Ravindranath * bit to be reset. 65589a36810SAnil Ravindranath */ 656c20c4267SAnil Ravindranath cmd->time_left = PMCRAID_RESET_TIMEOUT; 65789a36810SAnil Ravindranath cmd->timer.expires = jiffies + PMCRAID_CHECK_FOR_RESET_TIMEOUT; 658841b86f3SKees Cook cmd->timer.function = pmcraid_reset_alert_done; 65989a36810SAnil Ravindranath add_timer(&cmd->timer); 66089a36810SAnil Ravindranath 66189a36810SAnil Ravindranath iowrite32(DOORBELL_IOA_RESET_ALERT, 66289a36810SAnil Ravindranath pinstance->int_regs.host_ioa_interrupt_reg); 66389a36810SAnil Ravindranath doorbells = 66489a36810SAnil Ravindranath ioread32(pinstance->int_regs.host_ioa_interrupt_reg); 66589a36810SAnil Ravindranath pmcraid_info("doorbells after reset alert: %x\n", doorbells); 66689a36810SAnil Ravindranath } else { 66789a36810SAnil Ravindranath pmcraid_info("PCI config is not accessible starting BIST\n"); 66889a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_HARD_RESET; 66989a36810SAnil Ravindranath pmcraid_start_bist(cmd); 67089a36810SAnil Ravindranath } 67189a36810SAnil Ravindranath } 67289a36810SAnil Ravindranath 67389a36810SAnil Ravindranath /** 67489a36810SAnil Ravindranath * pmcraid_timeout_handler - Timeout handler for internally generated ops 67589a36810SAnil Ravindranath * 6763673b7b0SLee Jones * @t: pointer to command structure, that got timedout 67789a36810SAnil Ravindranath * 67889a36810SAnil Ravindranath * This function blocks host requests and initiates an adapter reset. 67989a36810SAnil Ravindranath * 68089a36810SAnil Ravindranath * Return value: 68189a36810SAnil Ravindranath * None 68289a36810SAnil Ravindranath */ 683242b5657SKees Cook static void pmcraid_timeout_handler(struct timer_list *t) 68489a36810SAnil Ravindranath { 685242b5657SKees Cook struct pmcraid_cmd *cmd = from_timer(cmd, t, timer); 68689a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 68789a36810SAnil Ravindranath unsigned long lock_flags; 68889a36810SAnil Ravindranath 68934876402SAnil Ravindranath dev_info(&pinstance->pdev->dev, 690c20c4267SAnil Ravindranath "Adapter being reset due to cmd(CDB[0] = %x) timeout\n", 691c20c4267SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0]); 69289a36810SAnil Ravindranath 69389a36810SAnil Ravindranath /* Command timeouts result in hard reset sequence. The command that got 69489a36810SAnil Ravindranath * timed out may be the one used as part of reset sequence. In this 69589a36810SAnil Ravindranath * case restart reset sequence using the same command block even if 69689a36810SAnil Ravindranath * reset is in progress. Otherwise fail this command and get a free 69789a36810SAnil Ravindranath * command block to restart the reset sequence. 69889a36810SAnil Ravindranath */ 69989a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 70089a36810SAnil Ravindranath if (!pinstance->ioa_reset_in_progress) { 70189a36810SAnil Ravindranath pinstance->ioa_reset_attempts = 0; 70289a36810SAnil Ravindranath cmd = pmcraid_get_free_cmd(pinstance); 70389a36810SAnil Ravindranath 70489a36810SAnil Ravindranath /* If we are out of command blocks, just return here itself. 70589a36810SAnil Ravindranath * Some other command's timeout handler can do the reset job 70689a36810SAnil Ravindranath */ 70789a36810SAnil Ravindranath if (cmd == NULL) { 70889a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 70989a36810SAnil Ravindranath lock_flags); 71089a36810SAnil Ravindranath pmcraid_err("no free cmnd block for timeout handler\n"); 71189a36810SAnil Ravindranath return; 71289a36810SAnil Ravindranath } 71389a36810SAnil Ravindranath 71489a36810SAnil Ravindranath pinstance->reset_cmd = cmd; 71589a36810SAnil Ravindranath pinstance->ioa_reset_in_progress = 1; 71689a36810SAnil Ravindranath } else { 71789a36810SAnil Ravindranath pmcraid_info("reset is already in progress\n"); 71889a36810SAnil Ravindranath 71989a36810SAnil Ravindranath if (pinstance->reset_cmd != cmd) { 72089a36810SAnil Ravindranath /* This command should have been given to IOA, this 72189a36810SAnil Ravindranath * command will be completed by fail_outstanding_cmds 72289a36810SAnil Ravindranath * anyway 72389a36810SAnil Ravindranath */ 72489a36810SAnil Ravindranath pmcraid_err("cmd is pending but reset in progress\n"); 72589a36810SAnil Ravindranath } 72689a36810SAnil Ravindranath 72789a36810SAnil Ravindranath /* If this command was being used as part of the reset 72889a36810SAnil Ravindranath * sequence, set cmd_done pointer to pmcraid_ioa_reset. This 72989a36810SAnil Ravindranath * causes fail_outstanding_commands not to return the command 73089a36810SAnil Ravindranath * block back to free pool 73189a36810SAnil Ravindranath */ 73289a36810SAnil Ravindranath if (cmd == pinstance->reset_cmd) 73389a36810SAnil Ravindranath cmd->cmd_done = pmcraid_ioa_reset; 73489a36810SAnil Ravindranath } 73589a36810SAnil Ravindranath 736c20c4267SAnil Ravindranath /* Notify apps of important IOA bringup/bringdown sequences */ 737c20c4267SAnil Ravindranath if (pinstance->scn.ioa_state != PMC_DEVICE_EVENT_RESET_START && 738c20c4267SAnil Ravindranath pinstance->scn.ioa_state != PMC_DEVICE_EVENT_SHUTDOWN_START) 739c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, 740c20c4267SAnil Ravindranath PMC_DEVICE_EVENT_RESET_START); 741c20c4267SAnil Ravindranath 74289a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; 74389a36810SAnil Ravindranath scsi_block_requests(pinstance->host); 74489a36810SAnil Ravindranath pmcraid_reset_alert(cmd); 74589a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 74689a36810SAnil Ravindranath } 74789a36810SAnil Ravindranath 74889a36810SAnil Ravindranath /** 74989a36810SAnil Ravindranath * pmcraid_internal_done - completion routine for internally generated cmds 75089a36810SAnil Ravindranath * 75189a36810SAnil Ravindranath * @cmd: command that got response from IOA 75289a36810SAnil Ravindranath * 75389a36810SAnil Ravindranath * Return Value: 75489a36810SAnil Ravindranath * none 75589a36810SAnil Ravindranath */ 75689a36810SAnil Ravindranath static void pmcraid_internal_done(struct pmcraid_cmd *cmd) 75789a36810SAnil Ravindranath { 75889a36810SAnil Ravindranath pmcraid_info("response internal cmd CDB[0] = %x ioasc = %x\n", 75989a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 76089a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)); 76189a36810SAnil Ravindranath 76289a36810SAnil Ravindranath /* Some of the internal commands are sent with callers blocking for the 76389a36810SAnil Ravindranath * response. Same will be indicated as part of cmd->completion_req 76489a36810SAnil Ravindranath * field. Response path needs to wake up any waiters waiting for cmd 76589a36810SAnil Ravindranath * completion if this flag is set. 76689a36810SAnil Ravindranath */ 76789a36810SAnil Ravindranath if (cmd->completion_req) { 76889a36810SAnil Ravindranath cmd->completion_req = 0; 76989a36810SAnil Ravindranath complete(&cmd->wait_for_completion); 77089a36810SAnil Ravindranath } 77189a36810SAnil Ravindranath 77289a36810SAnil Ravindranath /* most of the internal commands are completed by caller itself, so 77389a36810SAnil Ravindranath * no need to return the command block back to free pool until we are 77489a36810SAnil Ravindranath * required to do so (e.g once done with initialization). 77589a36810SAnil Ravindranath */ 77689a36810SAnil Ravindranath if (cmd->release) { 77789a36810SAnil Ravindranath cmd->release = 0; 77889a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 77989a36810SAnil Ravindranath } 78089a36810SAnil Ravindranath } 78189a36810SAnil Ravindranath 78289a36810SAnil Ravindranath /** 78389a36810SAnil Ravindranath * pmcraid_reinit_cfgtable_done - done function for cfg table reinitialization 78489a36810SAnil Ravindranath * 78589a36810SAnil Ravindranath * @cmd: command that got response from IOA 78689a36810SAnil Ravindranath * 78789a36810SAnil Ravindranath * This routine is called after driver re-reads configuration table due to a 78889a36810SAnil Ravindranath * lost CCN. It returns the command block back to free pool and schedules 78989a36810SAnil Ravindranath * worker thread to add/delete devices into the system. 79089a36810SAnil Ravindranath * 79189a36810SAnil Ravindranath * Return Value: 79289a36810SAnil Ravindranath * none 79389a36810SAnil Ravindranath */ 79489a36810SAnil Ravindranath static void pmcraid_reinit_cfgtable_done(struct pmcraid_cmd *cmd) 79589a36810SAnil Ravindranath { 79689a36810SAnil Ravindranath pmcraid_info("response internal cmd CDB[0] = %x ioasc = %x\n", 79789a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 79889a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)); 79989a36810SAnil Ravindranath 80089a36810SAnil Ravindranath if (cmd->release) { 80189a36810SAnil Ravindranath cmd->release = 0; 80289a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 80389a36810SAnil Ravindranath } 80489a36810SAnil Ravindranath pmcraid_info("scheduling worker for config table reinitialization\n"); 80589a36810SAnil Ravindranath schedule_work(&cmd->drv_inst->worker_q); 80689a36810SAnil Ravindranath } 80789a36810SAnil Ravindranath 80889a36810SAnil Ravindranath /** 80989a36810SAnil Ravindranath * pmcraid_erp_done - Process completion of SCSI error response from device 81089a36810SAnil Ravindranath * @cmd: pmcraid_command 81189a36810SAnil Ravindranath * 81289a36810SAnil Ravindranath * This function copies the sense buffer into the scsi_cmd struct and completes 81389a36810SAnil Ravindranath * scsi_cmd by calling scsi_done function. 81489a36810SAnil Ravindranath * 81589a36810SAnil Ravindranath * Return value: 81689a36810SAnil Ravindranath * none 81789a36810SAnil Ravindranath */ 81889a36810SAnil Ravindranath static void pmcraid_erp_done(struct pmcraid_cmd *cmd) 81989a36810SAnil Ravindranath { 82089a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; 82189a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 82289a36810SAnil Ravindranath u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); 82389a36810SAnil Ravindranath 82489a36810SAnil Ravindranath if (PMCRAID_IOASC_SENSE_KEY(ioasc) > 0) { 82589a36810SAnil Ravindranath scsi_cmd->result |= (DID_ERROR << 16); 82634876402SAnil Ravindranath scmd_printk(KERN_INFO, scsi_cmd, 82734876402SAnil Ravindranath "command CDB[0] = %x failed with IOASC: 0x%08X\n", 82889a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], ioasc); 82989a36810SAnil Ravindranath } 83089a36810SAnil Ravindranath 831a9b9e3adSChristoph Hellwig if (cmd->sense_buffer) { 832a9b9e3adSChristoph Hellwig dma_unmap_single(&pinstance->pdev->dev, cmd->sense_buffer_dma, 833a9b9e3adSChristoph Hellwig SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); 83489a36810SAnil Ravindranath cmd->sense_buffer = NULL; 83589a36810SAnil Ravindranath cmd->sense_buffer_dma = 0; 83689a36810SAnil Ravindranath } 83789a36810SAnil Ravindranath 83889a36810SAnil Ravindranath scsi_dma_unmap(scsi_cmd); 83989a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 840f13cc234SBart Van Assche scsi_done(scsi_cmd); 84189a36810SAnil Ravindranath } 84289a36810SAnil Ravindranath 84389a36810SAnil Ravindranath /** 8443673b7b0SLee Jones * _pmcraid_fire_command - sends an IOA command to adapter 84589a36810SAnil Ravindranath * 84689a36810SAnil Ravindranath * This function adds the given block into pending command list 84789a36810SAnil Ravindranath * and returns without waiting 84889a36810SAnil Ravindranath * 84989a36810SAnil Ravindranath * @cmd : command to be sent to the device 85089a36810SAnil Ravindranath * 85189a36810SAnil Ravindranath * Return Value 85289a36810SAnil Ravindranath * None 85389a36810SAnil Ravindranath */ 85489a36810SAnil Ravindranath static void _pmcraid_fire_command(struct pmcraid_cmd *cmd) 85589a36810SAnil Ravindranath { 85689a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 85789a36810SAnil Ravindranath unsigned long lock_flags; 85889a36810SAnil Ravindranath 85989a36810SAnil Ravindranath /* Add this command block to pending cmd pool. We do this prior to 86089a36810SAnil Ravindranath * writting IOARCB to ioarrin because IOA might complete the command 86189a36810SAnil Ravindranath * by the time we are about to add it to the list. Response handler 862c20c4267SAnil Ravindranath * (isr/tasklet) looks for cmd block in the pending pending list. 86389a36810SAnil Ravindranath */ 86489a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->pending_pool_lock, lock_flags); 86589a36810SAnil Ravindranath list_add_tail(&cmd->free_list, &pinstance->pending_cmd_pool); 86689a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->pending_pool_lock, lock_flags); 86789a36810SAnil Ravindranath atomic_inc(&pinstance->outstanding_cmds); 86889a36810SAnil Ravindranath 86989a36810SAnil Ravindranath /* driver writes lower 32-bit value of IOARCB address only */ 87089a36810SAnil Ravindranath mb(); 87145c80be6SArnd Bergmann iowrite32(le64_to_cpu(cmd->ioa_cb->ioarcb.ioarcb_bus_addr), pinstance->ioarrin); 87289a36810SAnil Ravindranath } 87389a36810SAnil Ravindranath 87489a36810SAnil Ravindranath /** 87589a36810SAnil Ravindranath * pmcraid_send_cmd - fires a command to IOA 87689a36810SAnil Ravindranath * 87789a36810SAnil Ravindranath * This function also sets up timeout function, and command completion 87889a36810SAnil Ravindranath * function 87989a36810SAnil Ravindranath * 88089a36810SAnil Ravindranath * @cmd: pointer to the command block to be fired to IOA 88189a36810SAnil Ravindranath * @cmd_done: command completion function, called once IOA responds 88289a36810SAnil Ravindranath * @timeout: timeout to wait for this command completion 88389a36810SAnil Ravindranath * @timeout_func: timeout handler 88489a36810SAnil Ravindranath * 88589a36810SAnil Ravindranath * Return value 88689a36810SAnil Ravindranath * none 88789a36810SAnil Ravindranath */ 88889a36810SAnil Ravindranath static void pmcraid_send_cmd( 88989a36810SAnil Ravindranath struct pmcraid_cmd *cmd, 89089a36810SAnil Ravindranath void (*cmd_done) (struct pmcraid_cmd *), 89189a36810SAnil Ravindranath unsigned long timeout, 892242b5657SKees Cook void (*timeout_func) (struct timer_list *) 89389a36810SAnil Ravindranath ) 89489a36810SAnil Ravindranath { 89589a36810SAnil Ravindranath /* initialize done function */ 89689a36810SAnil Ravindranath cmd->cmd_done = cmd_done; 89789a36810SAnil Ravindranath 89889a36810SAnil Ravindranath if (timeout_func) { 89989a36810SAnil Ravindranath /* setup timeout handler */ 90089a36810SAnil Ravindranath cmd->timer.expires = jiffies + timeout; 901841b86f3SKees Cook cmd->timer.function = timeout_func; 90289a36810SAnil Ravindranath add_timer(&cmd->timer); 90389a36810SAnil Ravindranath } 90489a36810SAnil Ravindranath 90589a36810SAnil Ravindranath /* fire the command to IOA */ 90689a36810SAnil Ravindranath _pmcraid_fire_command(cmd); 90789a36810SAnil Ravindranath } 90889a36810SAnil Ravindranath 90989a36810SAnil Ravindranath /** 910c20c4267SAnil Ravindranath * pmcraid_ioa_shutdown_done - completion function for IOA shutdown command 911c20c4267SAnil Ravindranath * @cmd: pointer to the command block used for sending IOA shutdown command 912c20c4267SAnil Ravindranath * 913c20c4267SAnil Ravindranath * Return value 914c20c4267SAnil Ravindranath * None 915c20c4267SAnil Ravindranath */ 916c20c4267SAnil Ravindranath static void pmcraid_ioa_shutdown_done(struct pmcraid_cmd *cmd) 917c20c4267SAnil Ravindranath { 918c20c4267SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 919c20c4267SAnil Ravindranath unsigned long lock_flags; 920c20c4267SAnil Ravindranath 921c20c4267SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 922c20c4267SAnil Ravindranath pmcraid_ioa_reset(cmd); 923c20c4267SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 924c20c4267SAnil Ravindranath } 925c20c4267SAnil Ravindranath 926c20c4267SAnil Ravindranath /** 92789a36810SAnil Ravindranath * pmcraid_ioa_shutdown - sends SHUTDOWN command to ioa 92889a36810SAnil Ravindranath * 92989a36810SAnil Ravindranath * @cmd: pointer to the command block used as part of reset sequence 93089a36810SAnil Ravindranath * 93189a36810SAnil Ravindranath * Return Value 93289a36810SAnil Ravindranath * None 93389a36810SAnil Ravindranath */ 93489a36810SAnil Ravindranath static void pmcraid_ioa_shutdown(struct pmcraid_cmd *cmd) 93589a36810SAnil Ravindranath { 93689a36810SAnil Ravindranath pmcraid_info("response for Cancel CCN CDB[0] = %x ioasc = %x\n", 93789a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 93889a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)); 93989a36810SAnil Ravindranath 94089a36810SAnil Ravindranath /* Note that commands sent during reset require next command to be sent 94189a36810SAnil Ravindranath * to IOA. Hence reinit the done function as well as timeout function 94289a36810SAnil Ravindranath */ 94389a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 94489a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.request_type = REQ_TYPE_IOACMD; 94589a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.resource_handle = 94689a36810SAnil Ravindranath cpu_to_le32(PMCRAID_IOA_RES_HANDLE); 94789a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0] = PMCRAID_IOA_SHUTDOWN; 94889a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[1] = PMCRAID_SHUTDOWN_NORMAL; 94989a36810SAnil Ravindranath 95089a36810SAnil Ravindranath /* fire shutdown command to hardware. */ 95189a36810SAnil Ravindranath pmcraid_info("firing normal shutdown command (%d) to IOA\n", 95289a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle)); 95389a36810SAnil Ravindranath 954c20c4267SAnil Ravindranath pmcraid_notify_ioastate(cmd->drv_inst, PMC_DEVICE_EVENT_SHUTDOWN_START); 955c20c4267SAnil Ravindranath 956c20c4267SAnil Ravindranath pmcraid_send_cmd(cmd, pmcraid_ioa_shutdown_done, 95789a36810SAnil Ravindranath PMCRAID_SHUTDOWN_TIMEOUT, 95889a36810SAnil Ravindranath pmcraid_timeout_handler); 95989a36810SAnil Ravindranath } 96089a36810SAnil Ravindranath 9613673b7b0SLee Jones static void pmcraid_querycfg(struct pmcraid_cmd *); 96289a36810SAnil Ravindranath /** 963c20c4267SAnil Ravindranath * pmcraid_get_fwversion_done - completion function for get_fwversion 964c20c4267SAnil Ravindranath * 965c20c4267SAnil Ravindranath * @cmd: pointer to command block used to send INQUIRY command 966c20c4267SAnil Ravindranath * 967c20c4267SAnil Ravindranath * Return Value 968c20c4267SAnil Ravindranath * none 969c20c4267SAnil Ravindranath */ 970c20c4267SAnil Ravindranath static void pmcraid_get_fwversion_done(struct pmcraid_cmd *cmd) 971c20c4267SAnil Ravindranath { 972c20c4267SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 973c20c4267SAnil Ravindranath u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); 974c20c4267SAnil Ravindranath unsigned long lock_flags; 975c20c4267SAnil Ravindranath 976c20c4267SAnil Ravindranath /* configuration table entry size depends on firmware version. If fw 977c20c4267SAnil Ravindranath * version is not known, it is not possible to interpret IOA config 978c20c4267SAnil Ravindranath * table 979c20c4267SAnil Ravindranath */ 980c20c4267SAnil Ravindranath if (ioasc) { 981c20c4267SAnil Ravindranath pmcraid_err("IOA Inquiry failed with %x\n", ioasc); 982c20c4267SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 983c20c4267SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; 984c20c4267SAnil Ravindranath pmcraid_reset_alert(cmd); 985c20c4267SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 986c20c4267SAnil Ravindranath } else { 987c20c4267SAnil Ravindranath pmcraid_querycfg(cmd); 988c20c4267SAnil Ravindranath } 989c20c4267SAnil Ravindranath } 990c20c4267SAnil Ravindranath 991c20c4267SAnil Ravindranath /** 992c20c4267SAnil Ravindranath * pmcraid_get_fwversion - reads firmware version information 993c20c4267SAnil Ravindranath * 994c20c4267SAnil Ravindranath * @cmd: pointer to command block used to send INQUIRY command 995c20c4267SAnil Ravindranath * 996c20c4267SAnil Ravindranath * Return Value 997c20c4267SAnil Ravindranath * none 998c20c4267SAnil Ravindranath */ 999c20c4267SAnil Ravindranath static void pmcraid_get_fwversion(struct pmcraid_cmd *cmd) 1000c20c4267SAnil Ravindranath { 1001c20c4267SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 1002b22ee87dSColin Ian King struct pmcraid_ioadl_desc *ioadl; 1003c20c4267SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 1004c20c4267SAnil Ravindranath u16 data_size = sizeof(struct pmcraid_inquiry_data); 1005c20c4267SAnil Ravindranath 1006c20c4267SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 1007c20c4267SAnil Ravindranath ioarcb->request_type = REQ_TYPE_SCSI; 1008c20c4267SAnil Ravindranath ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); 1009c20c4267SAnil Ravindranath ioarcb->cdb[0] = INQUIRY; 1010c20c4267SAnil Ravindranath ioarcb->cdb[1] = 1; 1011c20c4267SAnil Ravindranath ioarcb->cdb[2] = 0xD0; 1012c20c4267SAnil Ravindranath ioarcb->cdb[3] = (data_size >> 8) & 0xFF; 1013c20c4267SAnil Ravindranath ioarcb->cdb[4] = data_size & 0xFF; 1014c20c4267SAnil Ravindranath 1015c20c4267SAnil Ravindranath /* Since entire inquiry data it can be part of IOARCB itself 1016c20c4267SAnil Ravindranath */ 1017c20c4267SAnil Ravindranath ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + 1018c20c4267SAnil Ravindranath offsetof(struct pmcraid_ioarcb, 1019c20c4267SAnil Ravindranath add_data.u.ioadl[0])); 1020c20c4267SAnil Ravindranath ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); 102145c80be6SArnd Bergmann ioarcb->ioarcb_bus_addr &= cpu_to_le64(~(0x1FULL)); 1022c20c4267SAnil Ravindranath 1023c20c4267SAnil Ravindranath ioarcb->request_flags0 |= NO_LINK_DESCS; 1024c20c4267SAnil Ravindranath ioarcb->data_transfer_length = cpu_to_le32(data_size); 1025c20c4267SAnil Ravindranath ioadl = &(ioarcb->add_data.u.ioadl[0]); 1026c20c4267SAnil Ravindranath ioadl->flags = IOADL_FLAGS_LAST_DESC; 1027c20c4267SAnil Ravindranath ioadl->address = cpu_to_le64(pinstance->inq_data_baddr); 1028c20c4267SAnil Ravindranath ioadl->data_len = cpu_to_le32(data_size); 1029c20c4267SAnil Ravindranath 1030c20c4267SAnil Ravindranath pmcraid_send_cmd(cmd, pmcraid_get_fwversion_done, 1031c20c4267SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler); 1032c20c4267SAnil Ravindranath } 1033c20c4267SAnil Ravindranath 1034c20c4267SAnil Ravindranath /** 103589a36810SAnil Ravindranath * pmcraid_identify_hrrq - registers host rrq buffers with IOA 103689a36810SAnil Ravindranath * @cmd: pointer to command block to be used for identify hrrq 103789a36810SAnil Ravindranath * 103889a36810SAnil Ravindranath * Return Value 1039c20c4267SAnil Ravindranath * none 104089a36810SAnil Ravindranath */ 104189a36810SAnil Ravindranath static void pmcraid_identify_hrrq(struct pmcraid_cmd *cmd) 104289a36810SAnil Ravindranath { 104389a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 104489a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 1045c20c4267SAnil Ravindranath int index = cmd->hrrq_index; 104689a36810SAnil Ravindranath __be64 hrrq_addr = cpu_to_be64(pinstance->hrrq_start_bus_addr[index]); 104745c80be6SArnd Bergmann __be32 hrrq_size = cpu_to_be32(sizeof(u32) * PMCRAID_MAX_CMD); 1048c20c4267SAnil Ravindranath void (*done_function)(struct pmcraid_cmd *); 104989a36810SAnil Ravindranath 105089a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 1051c20c4267SAnil Ravindranath cmd->hrrq_index = index + 1; 1052c20c4267SAnil Ravindranath 1053c20c4267SAnil Ravindranath if (cmd->hrrq_index < pinstance->num_hrrq) { 1054c20c4267SAnil Ravindranath done_function = pmcraid_identify_hrrq; 1055c20c4267SAnil Ravindranath } else { 1056c20c4267SAnil Ravindranath cmd->hrrq_index = 0; 1057c20c4267SAnil Ravindranath done_function = pmcraid_get_fwversion; 1058c20c4267SAnil Ravindranath } 105989a36810SAnil Ravindranath 106089a36810SAnil Ravindranath /* Initialize ioarcb */ 106189a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_IOACMD; 106289a36810SAnil Ravindranath ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); 106389a36810SAnil Ravindranath 106489a36810SAnil Ravindranath /* initialize the hrrq number where IOA will respond to this command */ 106589a36810SAnil Ravindranath ioarcb->hrrq_id = index; 106689a36810SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_IDENTIFY_HRRQ; 106789a36810SAnil Ravindranath ioarcb->cdb[1] = index; 106889a36810SAnil Ravindranath 106989a36810SAnil Ravindranath /* IOA expects 64-bit pci address to be written in B.E format 107089a36810SAnil Ravindranath * (i.e cdb[2]=MSByte..cdb[9]=LSB. 107189a36810SAnil Ravindranath */ 1072c20c4267SAnil Ravindranath pmcraid_info("HRRQ_IDENTIFY with hrrq:ioarcb:index => %llx:%llx:%x\n", 1073c20c4267SAnil Ravindranath hrrq_addr, ioarcb->ioarcb_bus_addr, index); 107489a36810SAnil Ravindranath 107589a36810SAnil Ravindranath memcpy(&(ioarcb->cdb[2]), &hrrq_addr, sizeof(hrrq_addr)); 107689a36810SAnil Ravindranath memcpy(&(ioarcb->cdb[10]), &hrrq_size, sizeof(hrrq_size)); 107789a36810SAnil Ravindranath 107889a36810SAnil Ravindranath /* Subsequent commands require HRRQ identification to be successful. 107989a36810SAnil Ravindranath * Note that this gets called even during reset from SCSI mid-layer 108089a36810SAnil Ravindranath * or tasklet 108189a36810SAnil Ravindranath */ 1082c20c4267SAnil Ravindranath pmcraid_send_cmd(cmd, done_function, 108389a36810SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, 108489a36810SAnil Ravindranath pmcraid_timeout_handler); 108589a36810SAnil Ravindranath } 108689a36810SAnil Ravindranath 108789a36810SAnil Ravindranath static void pmcraid_process_ccn(struct pmcraid_cmd *cmd); 108889a36810SAnil Ravindranath static void pmcraid_process_ldn(struct pmcraid_cmd *cmd); 108989a36810SAnil Ravindranath 109089a36810SAnil Ravindranath /** 109189a36810SAnil Ravindranath * pmcraid_send_hcam_cmd - send an initialized command block(HCAM) to IOA 109289a36810SAnil Ravindranath * 109389a36810SAnil Ravindranath * @cmd: initialized command block pointer 109489a36810SAnil Ravindranath * 109589a36810SAnil Ravindranath * Return Value 109689a36810SAnil Ravindranath * none 109789a36810SAnil Ravindranath */ 109889a36810SAnil Ravindranath static void pmcraid_send_hcam_cmd(struct pmcraid_cmd *cmd) 109989a36810SAnil Ravindranath { 110089a36810SAnil Ravindranath if (cmd->ioa_cb->ioarcb.cdb[1] == PMCRAID_HCAM_CODE_CONFIG_CHANGE) 110189a36810SAnil Ravindranath atomic_set(&(cmd->drv_inst->ccn.ignore), 0); 110289a36810SAnil Ravindranath else 110389a36810SAnil Ravindranath atomic_set(&(cmd->drv_inst->ldn.ignore), 0); 110489a36810SAnil Ravindranath 110589a36810SAnil Ravindranath pmcraid_send_cmd(cmd, cmd->cmd_done, 0, NULL); 110689a36810SAnil Ravindranath } 110789a36810SAnil Ravindranath 110889a36810SAnil Ravindranath /** 110989a36810SAnil Ravindranath * pmcraid_init_hcam - send an initialized command block(HCAM) to IOA 111089a36810SAnil Ravindranath * 111189a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 111289a36810SAnil Ravindranath * @type: HCAM type 111389a36810SAnil Ravindranath * 111489a36810SAnil Ravindranath * Return Value 111589a36810SAnil Ravindranath * pointer to initialized pmcraid_cmd structure or NULL 111689a36810SAnil Ravindranath */ 111789a36810SAnil Ravindranath static struct pmcraid_cmd *pmcraid_init_hcam 111889a36810SAnil Ravindranath ( 111989a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 112089a36810SAnil Ravindranath u8 type 112189a36810SAnil Ravindranath ) 112289a36810SAnil Ravindranath { 112389a36810SAnil Ravindranath struct pmcraid_cmd *cmd; 112489a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb; 112589a36810SAnil Ravindranath struct pmcraid_ioadl_desc *ioadl; 112689a36810SAnil Ravindranath struct pmcraid_hostrcb *hcam; 112789a36810SAnil Ravindranath void (*cmd_done) (struct pmcraid_cmd *); 112889a36810SAnil Ravindranath dma_addr_t dma; 112989a36810SAnil Ravindranath int rcb_size; 113089a36810SAnil Ravindranath 113189a36810SAnil Ravindranath cmd = pmcraid_get_free_cmd(pinstance); 113289a36810SAnil Ravindranath 113389a36810SAnil Ravindranath if (!cmd) { 113489a36810SAnil Ravindranath pmcraid_err("no free command blocks for hcam\n"); 113589a36810SAnil Ravindranath return cmd; 113689a36810SAnil Ravindranath } 113789a36810SAnil Ravindranath 113889a36810SAnil Ravindranath if (type == PMCRAID_HCAM_CODE_CONFIG_CHANGE) { 1139c20c4267SAnil Ravindranath rcb_size = sizeof(struct pmcraid_hcam_ccn_ext); 114089a36810SAnil Ravindranath cmd_done = pmcraid_process_ccn; 114189a36810SAnil Ravindranath dma = pinstance->ccn.baddr + PMCRAID_AEN_HDR_SIZE; 114289a36810SAnil Ravindranath hcam = &pinstance->ccn; 114389a36810SAnil Ravindranath } else { 114489a36810SAnil Ravindranath rcb_size = sizeof(struct pmcraid_hcam_ldn); 114589a36810SAnil Ravindranath cmd_done = pmcraid_process_ldn; 114689a36810SAnil Ravindranath dma = pinstance->ldn.baddr + PMCRAID_AEN_HDR_SIZE; 114789a36810SAnil Ravindranath hcam = &pinstance->ldn; 114889a36810SAnil Ravindranath } 114989a36810SAnil Ravindranath 115089a36810SAnil Ravindranath /* initialize command pointer used for HCAM registration */ 115189a36810SAnil Ravindranath hcam->cmd = cmd; 115289a36810SAnil Ravindranath 115389a36810SAnil Ravindranath ioarcb = &cmd->ioa_cb->ioarcb; 115489a36810SAnil Ravindranath ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + 115589a36810SAnil Ravindranath offsetof(struct pmcraid_ioarcb, 115689a36810SAnil Ravindranath add_data.u.ioadl[0])); 115789a36810SAnil Ravindranath ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); 115889a36810SAnil Ravindranath ioadl = ioarcb->add_data.u.ioadl; 115989a36810SAnil Ravindranath 116089a36810SAnil Ravindranath /* Initialize ioarcb */ 116189a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_HCAM; 116289a36810SAnil Ravindranath ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); 116389a36810SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_HOST_CONTROLLED_ASYNC; 116489a36810SAnil Ravindranath ioarcb->cdb[1] = type; 116589a36810SAnil Ravindranath ioarcb->cdb[7] = (rcb_size >> 8) & 0xFF; 116689a36810SAnil Ravindranath ioarcb->cdb[8] = (rcb_size) & 0xFF; 116789a36810SAnil Ravindranath 116889a36810SAnil Ravindranath ioarcb->data_transfer_length = cpu_to_le32(rcb_size); 116989a36810SAnil Ravindranath 117088197966SAnil Ravindranath ioadl[0].flags |= IOADL_FLAGS_READ_LAST; 117189a36810SAnil Ravindranath ioadl[0].data_len = cpu_to_le32(rcb_size); 117245c80be6SArnd Bergmann ioadl[0].address = cpu_to_le64(dma); 117389a36810SAnil Ravindranath 117489a36810SAnil Ravindranath cmd->cmd_done = cmd_done; 117589a36810SAnil Ravindranath return cmd; 117689a36810SAnil Ravindranath } 117789a36810SAnil Ravindranath 117889a36810SAnil Ravindranath /** 117989a36810SAnil Ravindranath * pmcraid_send_hcam - Send an HCAM to IOA 118089a36810SAnil Ravindranath * @pinstance: ioa config struct 118189a36810SAnil Ravindranath * @type: HCAM type 118289a36810SAnil Ravindranath * 118389a36810SAnil Ravindranath * This function will send a Host Controlled Async command to IOA. 118489a36810SAnil Ravindranath * 118589a36810SAnil Ravindranath * Return value: 118689a36810SAnil Ravindranath * none 118789a36810SAnil Ravindranath */ 118889a36810SAnil Ravindranath static void pmcraid_send_hcam(struct pmcraid_instance *pinstance, u8 type) 118989a36810SAnil Ravindranath { 119089a36810SAnil Ravindranath struct pmcraid_cmd *cmd = pmcraid_init_hcam(pinstance, type); 119189a36810SAnil Ravindranath pmcraid_send_hcam_cmd(cmd); 119289a36810SAnil Ravindranath } 119389a36810SAnil Ravindranath 119489a36810SAnil Ravindranath 119589a36810SAnil Ravindranath /** 119689a36810SAnil Ravindranath * pmcraid_prepare_cancel_cmd - prepares a command block to abort another 119789a36810SAnil Ravindranath * 119889a36810SAnil Ravindranath * @cmd: pointer to cmd that is used as cancelling command 119989a36810SAnil Ravindranath * @cmd_to_cancel: pointer to the command that needs to be cancelled 120089a36810SAnil Ravindranath */ 120189a36810SAnil Ravindranath static void pmcraid_prepare_cancel_cmd( 120289a36810SAnil Ravindranath struct pmcraid_cmd *cmd, 120389a36810SAnil Ravindranath struct pmcraid_cmd *cmd_to_cancel 120489a36810SAnil Ravindranath ) 120589a36810SAnil Ravindranath { 120689a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 120745c80be6SArnd Bergmann __be64 ioarcb_addr; 120845c80be6SArnd Bergmann 120945c80be6SArnd Bergmann /* IOARCB address of the command to be cancelled is given in 121045c80be6SArnd Bergmann * cdb[2]..cdb[9] is Big-Endian format. Note that length bits in 121145c80be6SArnd Bergmann * IOARCB address are not masked. 121245c80be6SArnd Bergmann */ 121345c80be6SArnd Bergmann ioarcb_addr = cpu_to_be64(le64_to_cpu(cmd_to_cancel->ioa_cb->ioarcb.ioarcb_bus_addr)); 121489a36810SAnil Ravindranath 121589a36810SAnil Ravindranath /* Get the resource handle to where the command to be aborted has been 121689a36810SAnil Ravindranath * sent. 121789a36810SAnil Ravindranath */ 121889a36810SAnil Ravindranath ioarcb->resource_handle = cmd_to_cancel->ioa_cb->ioarcb.resource_handle; 121989a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_IOACMD; 122089a36810SAnil Ravindranath memset(ioarcb->cdb, 0, PMCRAID_MAX_CDB_LEN); 122189a36810SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_ABORT_CMD; 122289a36810SAnil Ravindranath 122389a36810SAnil Ravindranath memcpy(&(ioarcb->cdb[2]), &ioarcb_addr, sizeof(ioarcb_addr)); 122489a36810SAnil Ravindranath } 122589a36810SAnil Ravindranath 122689a36810SAnil Ravindranath /** 122789a36810SAnil Ravindranath * pmcraid_cancel_hcam - sends ABORT task to abort a given HCAM 122889a36810SAnil Ravindranath * 122989a36810SAnil Ravindranath * @cmd: command to be used as cancelling command 123089a36810SAnil Ravindranath * @type: HCAM type 123189a36810SAnil Ravindranath * @cmd_done: op done function for the cancelling command 123289a36810SAnil Ravindranath */ 123389a36810SAnil Ravindranath static void pmcraid_cancel_hcam( 123489a36810SAnil Ravindranath struct pmcraid_cmd *cmd, 123589a36810SAnil Ravindranath u8 type, 123689a36810SAnil Ravindranath void (*cmd_done) (struct pmcraid_cmd *) 123789a36810SAnil Ravindranath ) 123889a36810SAnil Ravindranath { 123989a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 124089a36810SAnil Ravindranath struct pmcraid_hostrcb *hcam; 124189a36810SAnil Ravindranath 124289a36810SAnil Ravindranath pinstance = cmd->drv_inst; 124389a36810SAnil Ravindranath hcam = (type == PMCRAID_HCAM_CODE_LOG_DATA) ? 124489a36810SAnil Ravindranath &pinstance->ldn : &pinstance->ccn; 124589a36810SAnil Ravindranath 124689a36810SAnil Ravindranath /* prepare for cancelling previous hcam command. If the HCAM is 124789a36810SAnil Ravindranath * currently not pending with IOA, we would have hcam->cmd as non-null 124889a36810SAnil Ravindranath */ 124989a36810SAnil Ravindranath if (hcam->cmd == NULL) 125089a36810SAnil Ravindranath return; 125189a36810SAnil Ravindranath 125289a36810SAnil Ravindranath pmcraid_prepare_cancel_cmd(cmd, hcam->cmd); 125389a36810SAnil Ravindranath 125489a36810SAnil Ravindranath /* writing to IOARRIN must be protected by host_lock, as mid-layer 125589a36810SAnil Ravindranath * schedule queuecommand while we are doing this 125689a36810SAnil Ravindranath */ 125789a36810SAnil Ravindranath pmcraid_send_cmd(cmd, cmd_done, 125889a36810SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, 125989a36810SAnil Ravindranath pmcraid_timeout_handler); 126089a36810SAnil Ravindranath } 126189a36810SAnil Ravindranath 126289a36810SAnil Ravindranath /** 126389a36810SAnil Ravindranath * pmcraid_cancel_ccn - cancel CCN HCAM already registered with IOA 126489a36810SAnil Ravindranath * 126589a36810SAnil Ravindranath * @cmd: command block to be used for cancelling the HCAM 126689a36810SAnil Ravindranath */ 126789a36810SAnil Ravindranath static void pmcraid_cancel_ccn(struct pmcraid_cmd *cmd) 126889a36810SAnil Ravindranath { 126989a36810SAnil Ravindranath pmcraid_info("response for Cancel LDN CDB[0] = %x ioasc = %x\n", 127089a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 127189a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)); 127289a36810SAnil Ravindranath 127389a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 127489a36810SAnil Ravindranath 127589a36810SAnil Ravindranath pmcraid_cancel_hcam(cmd, 127689a36810SAnil Ravindranath PMCRAID_HCAM_CODE_CONFIG_CHANGE, 127789a36810SAnil Ravindranath pmcraid_ioa_shutdown); 127889a36810SAnil Ravindranath } 127989a36810SAnil Ravindranath 128089a36810SAnil Ravindranath /** 128189a36810SAnil Ravindranath * pmcraid_cancel_ldn - cancel LDN HCAM already registered with IOA 128289a36810SAnil Ravindranath * 128389a36810SAnil Ravindranath * @cmd: command block to be used for cancelling the HCAM 128489a36810SAnil Ravindranath */ 128589a36810SAnil Ravindranath static void pmcraid_cancel_ldn(struct pmcraid_cmd *cmd) 128689a36810SAnil Ravindranath { 128789a36810SAnil Ravindranath pmcraid_cancel_hcam(cmd, 128889a36810SAnil Ravindranath PMCRAID_HCAM_CODE_LOG_DATA, 128989a36810SAnil Ravindranath pmcraid_cancel_ccn); 129089a36810SAnil Ravindranath } 129189a36810SAnil Ravindranath 129289a36810SAnil Ravindranath /** 129389a36810SAnil Ravindranath * pmcraid_expose_resource - check if the resource can be exposed to OS 129489a36810SAnil Ravindranath * 1295c20c4267SAnil Ravindranath * @fw_version: firmware version code 129689a36810SAnil Ravindranath * @cfgte: pointer to configuration table entry of the resource 129789a36810SAnil Ravindranath * 129889a36810SAnil Ravindranath * Return value: 129989a36810SAnil Ravindranath * true if resource can be added to midlayer, false(0) otherwise 130089a36810SAnil Ravindranath */ 1301c20c4267SAnil Ravindranath static int pmcraid_expose_resource(u16 fw_version, 1302c20c4267SAnil Ravindranath struct pmcraid_config_table_entry *cfgte) 130389a36810SAnil Ravindranath { 130489a36810SAnil Ravindranath int retval = 0; 130589a36810SAnil Ravindranath 1306c20c4267SAnil Ravindranath if (cfgte->resource_type == RES_TYPE_VSET) { 1307c20c4267SAnil Ravindranath if (fw_version <= PMCRAID_FW_VERSION_1) 1308729c8456SAnil Ravindranath retval = ((cfgte->unique_flags1 & 0x80) == 0); 1309c20c4267SAnil Ravindranath else 1310c20c4267SAnil Ravindranath retval = ((cfgte->unique_flags0 & 0x80) == 0 && 1311c20c4267SAnil Ravindranath (cfgte->unique_flags1 & 0x80) == 0); 1312c20c4267SAnil Ravindranath 1313c20c4267SAnil Ravindranath } else if (cfgte->resource_type == RES_TYPE_GSCSI) 131489a36810SAnil Ravindranath retval = (RES_BUS(cfgte->resource_address) != 131589a36810SAnil Ravindranath PMCRAID_VIRTUAL_ENCL_BUS_ID); 131689a36810SAnil Ravindranath return retval; 131789a36810SAnil Ravindranath } 131889a36810SAnil Ravindranath 131989a36810SAnil Ravindranath /* attributes supported by pmcraid_event_family */ 132089a36810SAnil Ravindranath enum { 132189a36810SAnil Ravindranath PMCRAID_AEN_ATTR_UNSPEC, 132289a36810SAnil Ravindranath PMCRAID_AEN_ATTR_EVENT, 132389a36810SAnil Ravindranath __PMCRAID_AEN_ATTR_MAX, 132489a36810SAnil Ravindranath }; 132589a36810SAnil Ravindranath #define PMCRAID_AEN_ATTR_MAX (__PMCRAID_AEN_ATTR_MAX - 1) 132689a36810SAnil Ravindranath 132789a36810SAnil Ravindranath /* commands supported by pmcraid_event_family */ 132889a36810SAnil Ravindranath enum { 132989a36810SAnil Ravindranath PMCRAID_AEN_CMD_UNSPEC, 133089a36810SAnil Ravindranath PMCRAID_AEN_CMD_EVENT, 133189a36810SAnil Ravindranath __PMCRAID_AEN_CMD_MAX, 133289a36810SAnil Ravindranath }; 133389a36810SAnil Ravindranath #define PMCRAID_AEN_CMD_MAX (__PMCRAID_AEN_CMD_MAX - 1) 133489a36810SAnil Ravindranath 13355e53e689SJohannes Berg static struct genl_multicast_group pmcraid_mcgrps[] = { 13365e53e689SJohannes Berg { .name = "events", /* not really used - see ID discussion below */ }, 13375e53e689SJohannes Berg }; 13385e53e689SJohannes Berg 133956989f6dSJohannes Berg static struct genl_family pmcraid_event_family __ro_after_init = { 1340489111e5SJohannes Berg .module = THIS_MODULE, 134189a36810SAnil Ravindranath .name = "pmcraid", 134289a36810SAnil Ravindranath .version = 1, 13435e53e689SJohannes Berg .maxattr = PMCRAID_AEN_ATTR_MAX, 13445e53e689SJohannes Berg .mcgrps = pmcraid_mcgrps, 13455e53e689SJohannes Berg .n_mcgrps = ARRAY_SIZE(pmcraid_mcgrps), 134689a36810SAnil Ravindranath }; 134789a36810SAnil Ravindranath 134889a36810SAnil Ravindranath /** 134989a36810SAnil Ravindranath * pmcraid_netlink_init - registers pmcraid_event_family 135089a36810SAnil Ravindranath * 135189a36810SAnil Ravindranath * Return value: 135289a36810SAnil Ravindranath * 0 if the pmcraid_event_family is successfully registered 135389a36810SAnil Ravindranath * with netlink generic, non-zero otherwise 135489a36810SAnil Ravindranath */ 135556989f6dSJohannes Berg static int __init pmcraid_netlink_init(void) 135689a36810SAnil Ravindranath { 135789a36810SAnil Ravindranath int result; 135889a36810SAnil Ravindranath 135989a36810SAnil Ravindranath result = genl_register_family(&pmcraid_event_family); 136089a36810SAnil Ravindranath 136189a36810SAnil Ravindranath if (result) 136289a36810SAnil Ravindranath return result; 136389a36810SAnil Ravindranath 136489a36810SAnil Ravindranath pmcraid_info("registered NETLINK GENERIC group: %d\n", 136589a36810SAnil Ravindranath pmcraid_event_family.id); 136689a36810SAnil Ravindranath 136789a36810SAnil Ravindranath return result; 136889a36810SAnil Ravindranath } 136989a36810SAnil Ravindranath 137089a36810SAnil Ravindranath /** 137189a36810SAnil Ravindranath * pmcraid_netlink_release - unregisters pmcraid_event_family 137289a36810SAnil Ravindranath * 137389a36810SAnil Ravindranath * Return value: 137489a36810SAnil Ravindranath * none 137589a36810SAnil Ravindranath */ 137689a36810SAnil Ravindranath static void pmcraid_netlink_release(void) 137789a36810SAnil Ravindranath { 137889a36810SAnil Ravindranath genl_unregister_family(&pmcraid_event_family); 137989a36810SAnil Ravindranath } 138089a36810SAnil Ravindranath 13813673b7b0SLee Jones /* 138289a36810SAnil Ravindranath * pmcraid_notify_aen - sends event msg to user space application 138389a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 138489a36810SAnil Ravindranath * 138589a36810SAnil Ravindranath * Return value: 138689a36810SAnil Ravindranath * 0 if success, error value in case of any failure. 138789a36810SAnil Ravindranath */ 1388c20c4267SAnil Ravindranath static int pmcraid_notify_aen( 1389c20c4267SAnil Ravindranath struct pmcraid_instance *pinstance, 1390c20c4267SAnil Ravindranath struct pmcraid_aen_msg *aen_msg, 13913673b7b0SLee Jones u32 data_size) 139289a36810SAnil Ravindranath { 139389a36810SAnil Ravindranath struct sk_buff *skb; 139489a36810SAnil Ravindranath void *msg_header; 1395c20c4267SAnil Ravindranath u32 total_size, nla_genl_hdr_total_size; 139689a36810SAnil Ravindranath int result; 139789a36810SAnil Ravindranath 139889a36810SAnil Ravindranath aen_msg->hostno = (pinstance->host->unique_id << 16 | 139989a36810SAnil Ravindranath MINOR(pinstance->cdev.dev)); 140089a36810SAnil Ravindranath aen_msg->length = data_size; 1401c20c4267SAnil Ravindranath 140289a36810SAnil Ravindranath data_size += sizeof(*aen_msg); 140389a36810SAnil Ravindranath 140489a36810SAnil Ravindranath total_size = nla_total_size(data_size); 1405c20c4267SAnil Ravindranath /* Add GENL_HDR to total_size */ 1406c20c4267SAnil Ravindranath nla_genl_hdr_total_size = 1407c20c4267SAnil Ravindranath (total_size + (GENL_HDRLEN + 1408c20c4267SAnil Ravindranath ((struct genl_family *)&pmcraid_event_family)->hdrsize) 1409c20c4267SAnil Ravindranath + NLMSG_HDRLEN); 1410c20c4267SAnil Ravindranath skb = genlmsg_new(nla_genl_hdr_total_size, GFP_ATOMIC); 141189a36810SAnil Ravindranath 141289a36810SAnil Ravindranath 141389a36810SAnil Ravindranath if (!skb) { 141489a36810SAnil Ravindranath pmcraid_err("Failed to allocate aen data SKB of size: %x\n", 141589a36810SAnil Ravindranath total_size); 141689a36810SAnil Ravindranath return -ENOMEM; 141789a36810SAnil Ravindranath } 141889a36810SAnil Ravindranath 141989a36810SAnil Ravindranath /* add the genetlink message header */ 142089a36810SAnil Ravindranath msg_header = genlmsg_put(skb, 0, 0, 142189a36810SAnil Ravindranath &pmcraid_event_family, 0, 142289a36810SAnil Ravindranath PMCRAID_AEN_CMD_EVENT); 142389a36810SAnil Ravindranath if (!msg_header) { 142489a36810SAnil Ravindranath pmcraid_err("failed to copy command details\n"); 142589a36810SAnil Ravindranath nlmsg_free(skb); 142689a36810SAnil Ravindranath return -ENOMEM; 142789a36810SAnil Ravindranath } 142889a36810SAnil Ravindranath 142989a36810SAnil Ravindranath result = nla_put(skb, PMCRAID_AEN_ATTR_EVENT, data_size, aen_msg); 143089a36810SAnil Ravindranath 143189a36810SAnil Ravindranath if (result) { 143289a36810SAnil Ravindranath pmcraid_err("failed to copy AEN attribute data\n"); 143389a36810SAnil Ravindranath nlmsg_free(skb); 143489a36810SAnil Ravindranath return -EINVAL; 143589a36810SAnil Ravindranath } 143689a36810SAnil Ravindranath 143789a36810SAnil Ravindranath /* send genetlink multicast message to notify appplications */ 1438053c095aSJohannes Berg genlmsg_end(skb, msg_header); 143989a36810SAnil Ravindranath 14405e53e689SJohannes Berg result = genlmsg_multicast(&pmcraid_event_family, skb, 14415e53e689SJohannes Berg 0, 0, GFP_ATOMIC); 144289a36810SAnil Ravindranath 144389a36810SAnil Ravindranath /* If there are no listeners, genlmsg_multicast may return non-zero 144489a36810SAnil Ravindranath * value. 144589a36810SAnil Ravindranath */ 144689a36810SAnil Ravindranath if (result) 1447c20c4267SAnil Ravindranath pmcraid_info("error (%x) sending aen event message\n", result); 144889a36810SAnil Ravindranath return result; 144989a36810SAnil Ravindranath } 145089a36810SAnil Ravindranath 145189a36810SAnil Ravindranath /** 1452c20c4267SAnil Ravindranath * pmcraid_notify_ccn - notifies about CCN event msg to user space 1453c20c4267SAnil Ravindranath * @pinstance: pointer adapter instance structure 1454c20c4267SAnil Ravindranath * 1455c20c4267SAnil Ravindranath * Return value: 1456c20c4267SAnil Ravindranath * 0 if success, error value in case of any failure 1457c20c4267SAnil Ravindranath */ 1458c20c4267SAnil Ravindranath static int pmcraid_notify_ccn(struct pmcraid_instance *pinstance) 1459c20c4267SAnil Ravindranath { 1460c20c4267SAnil Ravindranath return pmcraid_notify_aen(pinstance, 1461c20c4267SAnil Ravindranath pinstance->ccn.msg, 146245c80be6SArnd Bergmann le32_to_cpu(pinstance->ccn.hcam->data_len) + 1463c20c4267SAnil Ravindranath sizeof(struct pmcraid_hcam_hdr)); 1464c20c4267SAnil Ravindranath } 1465c20c4267SAnil Ravindranath 1466c20c4267SAnil Ravindranath /** 1467c20c4267SAnil Ravindranath * pmcraid_notify_ldn - notifies about CCN event msg to user space 1468c20c4267SAnil Ravindranath * @pinstance: pointer adapter instance structure 1469c20c4267SAnil Ravindranath * 1470c20c4267SAnil Ravindranath * Return value: 1471c20c4267SAnil Ravindranath * 0 if success, error value in case of any failure 1472c20c4267SAnil Ravindranath */ 1473c20c4267SAnil Ravindranath static int pmcraid_notify_ldn(struct pmcraid_instance *pinstance) 1474c20c4267SAnil Ravindranath { 1475c20c4267SAnil Ravindranath return pmcraid_notify_aen(pinstance, 1476c20c4267SAnil Ravindranath pinstance->ldn.msg, 147745c80be6SArnd Bergmann le32_to_cpu(pinstance->ldn.hcam->data_len) + 1478c20c4267SAnil Ravindranath sizeof(struct pmcraid_hcam_hdr)); 1479c20c4267SAnil Ravindranath } 1480c20c4267SAnil Ravindranath 1481c20c4267SAnil Ravindranath /** 1482c20c4267SAnil Ravindranath * pmcraid_notify_ioastate - sends IOA state event msg to user space 1483c20c4267SAnil Ravindranath * @pinstance: pointer adapter instance structure 1484c20c4267SAnil Ravindranath * @evt: controller state event to be sent 1485c20c4267SAnil Ravindranath * 1486c20c4267SAnil Ravindranath * Return value: 1487c20c4267SAnil Ravindranath * 0 if success, error value in case of any failure 1488c20c4267SAnil Ravindranath */ 1489c20c4267SAnil Ravindranath static void pmcraid_notify_ioastate(struct pmcraid_instance *pinstance, u32 evt) 1490c20c4267SAnil Ravindranath { 1491c20c4267SAnil Ravindranath pinstance->scn.ioa_state = evt; 1492c20c4267SAnil Ravindranath pmcraid_notify_aen(pinstance, 1493c20c4267SAnil Ravindranath &pinstance->scn.msg, 1494c20c4267SAnil Ravindranath sizeof(u32)); 1495c20c4267SAnil Ravindranath } 1496c20c4267SAnil Ravindranath 1497c20c4267SAnil Ravindranath /** 149889a36810SAnil Ravindranath * pmcraid_handle_config_change - Handle a config change from the adapter 149989a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 150089a36810SAnil Ravindranath * 150189a36810SAnil Ravindranath * Return value: 150289a36810SAnil Ravindranath * none 150389a36810SAnil Ravindranath */ 1504729c8456SAnil Ravindranath 150589a36810SAnil Ravindranath static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance) 150689a36810SAnil Ravindranath { 150789a36810SAnil Ravindranath struct pmcraid_config_table_entry *cfg_entry; 150889a36810SAnil Ravindranath struct pmcraid_hcam_ccn *ccn_hcam; 150989a36810SAnil Ravindranath struct pmcraid_cmd *cmd; 151089a36810SAnil Ravindranath struct pmcraid_cmd *cfgcmd; 151189a36810SAnil Ravindranath struct pmcraid_resource_entry *res = NULL; 151289a36810SAnil Ravindranath unsigned long lock_flags; 151389a36810SAnil Ravindranath unsigned long host_lock_flags; 1514729c8456SAnil Ravindranath u32 new_entry = 1; 1515729c8456SAnil Ravindranath u32 hidden_entry = 0; 1516c20c4267SAnil Ravindranath u16 fw_version; 151789a36810SAnil Ravindranath int rc; 151889a36810SAnil Ravindranath 151989a36810SAnil Ravindranath ccn_hcam = (struct pmcraid_hcam_ccn *)pinstance->ccn.hcam; 152089a36810SAnil Ravindranath cfg_entry = &ccn_hcam->cfg_entry; 1521c20c4267SAnil Ravindranath fw_version = be16_to_cpu(pinstance->inq_data->fw_version); 152289a36810SAnil Ravindranath 1523592488a3SAnil Ravindranath pmcraid_info("CCN(%x): %x timestamp: %llx type: %x lost: %x flags: %x \ 1524592488a3SAnil Ravindranath res: %x:%x:%x:%x\n", 152545c80be6SArnd Bergmann le32_to_cpu(pinstance->ccn.hcam->ilid), 152689a36810SAnil Ravindranath pinstance->ccn.hcam->op_code, 152745c80be6SArnd Bergmann (le32_to_cpu(pinstance->ccn.hcam->timestamp1) | 152845c80be6SArnd Bergmann ((le32_to_cpu(pinstance->ccn.hcam->timestamp2) & 0xffffffffLL) << 32)), 152989a36810SAnil Ravindranath pinstance->ccn.hcam->notification_type, 153089a36810SAnil Ravindranath pinstance->ccn.hcam->notification_lost, 153189a36810SAnil Ravindranath pinstance->ccn.hcam->flags, 153289a36810SAnil Ravindranath pinstance->host->unique_id, 153389a36810SAnil Ravindranath RES_IS_VSET(*cfg_entry) ? PMCRAID_VSET_BUS_ID : 153489a36810SAnil Ravindranath (RES_IS_GSCSI(*cfg_entry) ? PMCRAID_PHYS_BUS_ID : 153589a36810SAnil Ravindranath RES_BUS(cfg_entry->resource_address)), 1536c20c4267SAnil Ravindranath RES_IS_VSET(*cfg_entry) ? 1537c20c4267SAnil Ravindranath (fw_version <= PMCRAID_FW_VERSION_1 ? 1538c20c4267SAnil Ravindranath cfg_entry->unique_flags1 : 153945c80be6SArnd Bergmann le16_to_cpu(cfg_entry->array_id) & 0xFF) : 154089a36810SAnil Ravindranath RES_TARGET(cfg_entry->resource_address), 154189a36810SAnil Ravindranath RES_LUN(cfg_entry->resource_address)); 154289a36810SAnil Ravindranath 154389a36810SAnil Ravindranath 154489a36810SAnil Ravindranath /* If this HCAM indicates a lost notification, read the config table */ 154589a36810SAnil Ravindranath if (pinstance->ccn.hcam->notification_lost) { 154689a36810SAnil Ravindranath cfgcmd = pmcraid_get_free_cmd(pinstance); 154789a36810SAnil Ravindranath if (cfgcmd) { 154889a36810SAnil Ravindranath pmcraid_info("lost CCN, reading config table\b"); 154989a36810SAnil Ravindranath pinstance->reinit_cfg_table = 1; 155089a36810SAnil Ravindranath pmcraid_querycfg(cfgcmd); 155189a36810SAnil Ravindranath } else { 155289a36810SAnil Ravindranath pmcraid_err("lost CCN, no free cmd for querycfg\n"); 155389a36810SAnil Ravindranath } 155489a36810SAnil Ravindranath goto out_notify_apps; 155589a36810SAnil Ravindranath } 155689a36810SAnil Ravindranath 155789a36810SAnil Ravindranath /* If this resource is not going to be added to mid-layer, just notify 1558729c8456SAnil Ravindranath * applications and return. If this notification is about hiding a VSET 1559729c8456SAnil Ravindranath * resource, check if it was exposed already. 156089a36810SAnil Ravindranath */ 1561729c8456SAnil Ravindranath if (pinstance->ccn.hcam->notification_type == 1562729c8456SAnil Ravindranath NOTIFICATION_TYPE_ENTRY_CHANGED && 1563c20c4267SAnil Ravindranath cfg_entry->resource_type == RES_TYPE_VSET) { 1564c20c4267SAnil Ravindranath hidden_entry = (cfg_entry->unique_flags1 & 0x80) != 0; 1565c20c4267SAnil Ravindranath } else if (!pmcraid_expose_resource(fw_version, cfg_entry)) { 156689a36810SAnil Ravindranath goto out_notify_apps; 1567c20c4267SAnil Ravindranath } 156889a36810SAnil Ravindranath 156989a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->resource_lock, lock_flags); 157089a36810SAnil Ravindranath list_for_each_entry(res, &pinstance->used_res_q, queue) { 157189a36810SAnil Ravindranath rc = memcmp(&res->cfg_entry.resource_address, 157289a36810SAnil Ravindranath &cfg_entry->resource_address, 157389a36810SAnil Ravindranath sizeof(cfg_entry->resource_address)); 157489a36810SAnil Ravindranath if (!rc) { 157589a36810SAnil Ravindranath new_entry = 0; 157689a36810SAnil Ravindranath break; 157789a36810SAnil Ravindranath } 157889a36810SAnil Ravindranath } 157989a36810SAnil Ravindranath 158089a36810SAnil Ravindranath if (new_entry) { 158189a36810SAnil Ravindranath 1582729c8456SAnil Ravindranath if (hidden_entry) { 1583729c8456SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, 1584729c8456SAnil Ravindranath lock_flags); 1585729c8456SAnil Ravindranath goto out_notify_apps; 1586729c8456SAnil Ravindranath } 1587729c8456SAnil Ravindranath 158889a36810SAnil Ravindranath /* If there are more number of resources than what driver can 158989a36810SAnil Ravindranath * manage, do not notify the applications about the CCN. Just 159089a36810SAnil Ravindranath * ignore this notifications and re-register the same HCAM 159189a36810SAnil Ravindranath */ 159289a36810SAnil Ravindranath if (list_empty(&pinstance->free_res_q)) { 159389a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, 159489a36810SAnil Ravindranath lock_flags); 159589a36810SAnil Ravindranath pmcraid_err("too many resources attached\n"); 159689a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, 159789a36810SAnil Ravindranath host_lock_flags); 159889a36810SAnil Ravindranath pmcraid_send_hcam(pinstance, 159989a36810SAnil Ravindranath PMCRAID_HCAM_CODE_CONFIG_CHANGE); 160089a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 160189a36810SAnil Ravindranath host_lock_flags); 160289a36810SAnil Ravindranath return; 160389a36810SAnil Ravindranath } 160489a36810SAnil Ravindranath 160589a36810SAnil Ravindranath res = list_entry(pinstance->free_res_q.next, 160689a36810SAnil Ravindranath struct pmcraid_resource_entry, queue); 160789a36810SAnil Ravindranath 160889a36810SAnil Ravindranath list_del(&res->queue); 160989a36810SAnil Ravindranath res->scsi_dev = NULL; 161089a36810SAnil Ravindranath res->reset_progress = 0; 161189a36810SAnil Ravindranath list_add_tail(&res->queue, &pinstance->used_res_q); 161289a36810SAnil Ravindranath } 161389a36810SAnil Ravindranath 1614c20c4267SAnil Ravindranath memcpy(&res->cfg_entry, cfg_entry, pinstance->config_table_entry_size); 161589a36810SAnil Ravindranath 161689a36810SAnil Ravindranath if (pinstance->ccn.hcam->notification_type == 1617729c8456SAnil Ravindranath NOTIFICATION_TYPE_ENTRY_DELETED || hidden_entry) { 161889a36810SAnil Ravindranath if (res->scsi_dev) { 1619c20c4267SAnil Ravindranath if (fw_version <= PMCRAID_FW_VERSION_1) 1620729c8456SAnil Ravindranath res->cfg_entry.unique_flags1 &= 0x7F; 1621c20c4267SAnil Ravindranath else 162245c80be6SArnd Bergmann res->cfg_entry.array_id &= cpu_to_le16(0xFF); 162389a36810SAnil Ravindranath res->change_detected = RES_CHANGE_DEL; 162489a36810SAnil Ravindranath res->cfg_entry.resource_handle = 162589a36810SAnil Ravindranath PMCRAID_INVALID_RES_HANDLE; 162689a36810SAnil Ravindranath schedule_work(&pinstance->worker_q); 162789a36810SAnil Ravindranath } else { 162889a36810SAnil Ravindranath /* This may be one of the non-exposed resources */ 162989a36810SAnil Ravindranath list_move_tail(&res->queue, &pinstance->free_res_q); 163089a36810SAnil Ravindranath } 163189a36810SAnil Ravindranath } else if (!res->scsi_dev) { 163289a36810SAnil Ravindranath res->change_detected = RES_CHANGE_ADD; 163389a36810SAnil Ravindranath schedule_work(&pinstance->worker_q); 163489a36810SAnil Ravindranath } 163589a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); 163689a36810SAnil Ravindranath 163789a36810SAnil Ravindranath out_notify_apps: 163889a36810SAnil Ravindranath 163989a36810SAnil Ravindranath /* Notify configuration changes to registered applications.*/ 164089a36810SAnil Ravindranath if (!pmcraid_disable_aen) 1641c20c4267SAnil Ravindranath pmcraid_notify_ccn(pinstance); 164289a36810SAnil Ravindranath 164389a36810SAnil Ravindranath cmd = pmcraid_init_hcam(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE); 164489a36810SAnil Ravindranath if (cmd) 164589a36810SAnil Ravindranath pmcraid_send_hcam_cmd(cmd); 164689a36810SAnil Ravindranath } 164789a36810SAnil Ravindranath 164889a36810SAnil Ravindranath /** 164989a36810SAnil Ravindranath * pmcraid_get_error_info - return error string for an ioasc 165089a36810SAnil Ravindranath * @ioasc: ioasc code 165189a36810SAnil Ravindranath * Return Value 165289a36810SAnil Ravindranath * none 165389a36810SAnil Ravindranath */ 165489a36810SAnil Ravindranath static struct pmcraid_ioasc_error *pmcraid_get_error_info(u32 ioasc) 165589a36810SAnil Ravindranath { 165689a36810SAnil Ravindranath int i; 165789a36810SAnil Ravindranath for (i = 0; i < ARRAY_SIZE(pmcraid_ioasc_error_table); i++) { 165889a36810SAnil Ravindranath if (pmcraid_ioasc_error_table[i].ioasc_code == ioasc) 165989a36810SAnil Ravindranath return &pmcraid_ioasc_error_table[i]; 166089a36810SAnil Ravindranath } 166189a36810SAnil Ravindranath return NULL; 166289a36810SAnil Ravindranath } 166389a36810SAnil Ravindranath 166489a36810SAnil Ravindranath /** 166589a36810SAnil Ravindranath * pmcraid_ioasc_logger - log IOASC information based user-settings 166689a36810SAnil Ravindranath * @ioasc: ioasc code 166789a36810SAnil Ravindranath * @cmd: pointer to command that resulted in 'ioasc' 166889a36810SAnil Ravindranath */ 166961b96d5bSBaoyou Xie static void pmcraid_ioasc_logger(u32 ioasc, struct pmcraid_cmd *cmd) 167089a36810SAnil Ravindranath { 167189a36810SAnil Ravindranath struct pmcraid_ioasc_error *error_info = pmcraid_get_error_info(ioasc); 167289a36810SAnil Ravindranath 167389a36810SAnil Ravindranath if (error_info == NULL || 167489a36810SAnil Ravindranath cmd->drv_inst->current_log_level < error_info->log_level) 167589a36810SAnil Ravindranath return; 167689a36810SAnil Ravindranath 167789a36810SAnil Ravindranath /* log the error string */ 1678c20c4267SAnil Ravindranath pmcraid_err("cmd [%x] for resource %x failed with %x(%s)\n", 167989a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 168045c80be6SArnd Bergmann le32_to_cpu(cmd->ioa_cb->ioarcb.resource_handle), 168145c80be6SArnd Bergmann ioasc, error_info->error_string); 168289a36810SAnil Ravindranath } 168389a36810SAnil Ravindranath 168489a36810SAnil Ravindranath /** 168589a36810SAnil Ravindranath * pmcraid_handle_error_log - Handle a config change (error log) from the IOA 168689a36810SAnil Ravindranath * 168789a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 168889a36810SAnil Ravindranath * 168989a36810SAnil Ravindranath * Return value: 169089a36810SAnil Ravindranath * none 169189a36810SAnil Ravindranath */ 169289a36810SAnil Ravindranath static void pmcraid_handle_error_log(struct pmcraid_instance *pinstance) 169389a36810SAnil Ravindranath { 169489a36810SAnil Ravindranath struct pmcraid_hcam_ldn *hcam_ldn; 169589a36810SAnil Ravindranath u32 ioasc; 169689a36810SAnil Ravindranath 169789a36810SAnil Ravindranath hcam_ldn = (struct pmcraid_hcam_ldn *)pinstance->ldn.hcam; 169889a36810SAnil Ravindranath 169989a36810SAnil Ravindranath pmcraid_info 170089a36810SAnil Ravindranath ("LDN(%x): %x type: %x lost: %x flags: %x overlay id: %x\n", 170189a36810SAnil Ravindranath pinstance->ldn.hcam->ilid, 170289a36810SAnil Ravindranath pinstance->ldn.hcam->op_code, 170389a36810SAnil Ravindranath pinstance->ldn.hcam->notification_type, 170489a36810SAnil Ravindranath pinstance->ldn.hcam->notification_lost, 170589a36810SAnil Ravindranath pinstance->ldn.hcam->flags, 170689a36810SAnil Ravindranath pinstance->ldn.hcam->overlay_id); 170789a36810SAnil Ravindranath 170889a36810SAnil Ravindranath /* log only the errors, no need to log informational log entries */ 170989a36810SAnil Ravindranath if (pinstance->ldn.hcam->notification_type != 171089a36810SAnil Ravindranath NOTIFICATION_TYPE_ERROR_LOG) 171189a36810SAnil Ravindranath return; 171289a36810SAnil Ravindranath 171389a36810SAnil Ravindranath if (pinstance->ldn.hcam->notification_lost == 171489a36810SAnil Ravindranath HOSTRCB_NOTIFICATIONS_LOST) 171534876402SAnil Ravindranath dev_info(&pinstance->pdev->dev, "Error notifications lost\n"); 171689a36810SAnil Ravindranath 171789a36810SAnil Ravindranath ioasc = le32_to_cpu(hcam_ldn->error_log.fd_ioasc); 171889a36810SAnil Ravindranath 171989a36810SAnil Ravindranath if (ioasc == PMCRAID_IOASC_UA_BUS_WAS_RESET || 172089a36810SAnil Ravindranath ioasc == PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER) { 172134876402SAnil Ravindranath dev_info(&pinstance->pdev->dev, 172289a36810SAnil Ravindranath "UnitAttention due to IOA Bus Reset\n"); 172389a36810SAnil Ravindranath scsi_report_bus_reset( 172489a36810SAnil Ravindranath pinstance->host, 172589a36810SAnil Ravindranath RES_BUS(hcam_ldn->error_log.fd_ra)); 172689a36810SAnil Ravindranath } 172789a36810SAnil Ravindranath 172889a36810SAnil Ravindranath return; 172989a36810SAnil Ravindranath } 173089a36810SAnil Ravindranath 173189a36810SAnil Ravindranath /** 173289a36810SAnil Ravindranath * pmcraid_process_ccn - Op done function for a CCN. 173389a36810SAnil Ravindranath * @cmd: pointer to command struct 173489a36810SAnil Ravindranath * 173589a36810SAnil Ravindranath * This function is the op done function for a configuration 173689a36810SAnil Ravindranath * change notification 173789a36810SAnil Ravindranath * 173889a36810SAnil Ravindranath * Return value: 173989a36810SAnil Ravindranath * none 174089a36810SAnil Ravindranath */ 174189a36810SAnil Ravindranath static void pmcraid_process_ccn(struct pmcraid_cmd *cmd) 174289a36810SAnil Ravindranath { 174389a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 174489a36810SAnil Ravindranath u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); 174589a36810SAnil Ravindranath unsigned long lock_flags; 174689a36810SAnil Ravindranath 174789a36810SAnil Ravindranath pinstance->ccn.cmd = NULL; 174889a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 174989a36810SAnil Ravindranath 175089a36810SAnil Ravindranath /* If driver initiated IOA reset happened while this hcam was pending 175189a36810SAnil Ravindranath * with IOA, or IOA bringdown sequence is in progress, no need to 175289a36810SAnil Ravindranath * re-register the hcam 175389a36810SAnil Ravindranath */ 175489a36810SAnil Ravindranath if (ioasc == PMCRAID_IOASC_IOA_WAS_RESET || 175589a36810SAnil Ravindranath atomic_read(&pinstance->ccn.ignore) == 1) { 175689a36810SAnil Ravindranath return; 175789a36810SAnil Ravindranath } else if (ioasc) { 175834876402SAnil Ravindranath dev_info(&pinstance->pdev->dev, 175989a36810SAnil Ravindranath "Host RCB (CCN) failed with IOASC: 0x%08X\n", ioasc); 176089a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 176189a36810SAnil Ravindranath pmcraid_send_hcam(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE); 176289a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 176389a36810SAnil Ravindranath } else { 176489a36810SAnil Ravindranath pmcraid_handle_config_change(pinstance); 176589a36810SAnil Ravindranath } 176689a36810SAnil Ravindranath } 176789a36810SAnil Ravindranath 17683673b7b0SLee Jones static void pmcraid_initiate_reset(struct pmcraid_instance *); 17693673b7b0SLee Jones static void pmcraid_set_timestamp(struct pmcraid_cmd *cmd); 177089a36810SAnil Ravindranath /** 177189a36810SAnil Ravindranath * pmcraid_process_ldn - op done function for an LDN 177289a36810SAnil Ravindranath * @cmd: pointer to command block 177389a36810SAnil Ravindranath * 177489a36810SAnil Ravindranath * Return value 177589a36810SAnil Ravindranath * none 177689a36810SAnil Ravindranath */ 177789a36810SAnil Ravindranath static void pmcraid_process_ldn(struct pmcraid_cmd *cmd) 177889a36810SAnil Ravindranath { 177989a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 178089a36810SAnil Ravindranath struct pmcraid_hcam_ldn *ldn_hcam = 178189a36810SAnil Ravindranath (struct pmcraid_hcam_ldn *)pinstance->ldn.hcam; 178289a36810SAnil Ravindranath u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); 178389a36810SAnil Ravindranath u32 fd_ioasc = le32_to_cpu(ldn_hcam->error_log.fd_ioasc); 178489a36810SAnil Ravindranath unsigned long lock_flags; 178589a36810SAnil Ravindranath 178689a36810SAnil Ravindranath /* return the command block back to freepool */ 178789a36810SAnil Ravindranath pinstance->ldn.cmd = NULL; 178889a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 178989a36810SAnil Ravindranath 179089a36810SAnil Ravindranath /* If driver initiated IOA reset happened while this hcam was pending 179189a36810SAnil Ravindranath * with IOA, no need to re-register the hcam as reset engine will do it 179289a36810SAnil Ravindranath * once reset sequence is complete 179389a36810SAnil Ravindranath */ 179489a36810SAnil Ravindranath if (ioasc == PMCRAID_IOASC_IOA_WAS_RESET || 179589a36810SAnil Ravindranath atomic_read(&pinstance->ccn.ignore) == 1) { 179689a36810SAnil Ravindranath return; 179789a36810SAnil Ravindranath } else if (!ioasc) { 179889a36810SAnil Ravindranath pmcraid_handle_error_log(pinstance); 179989a36810SAnil Ravindranath if (fd_ioasc == PMCRAID_IOASC_NR_IOA_RESET_REQUIRED) { 180089a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, 180189a36810SAnil Ravindranath lock_flags); 180289a36810SAnil Ravindranath pmcraid_initiate_reset(pinstance); 180389a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 180489a36810SAnil Ravindranath lock_flags); 180589a36810SAnil Ravindranath return; 180689a36810SAnil Ravindranath } 1807592488a3SAnil Ravindranath if (fd_ioasc == PMCRAID_IOASC_TIME_STAMP_OUT_OF_SYNC) { 1808592488a3SAnil Ravindranath pinstance->timestamp_error = 1; 1809592488a3SAnil Ravindranath pmcraid_set_timestamp(cmd); 1810592488a3SAnil Ravindranath } 181189a36810SAnil Ravindranath } else { 181234876402SAnil Ravindranath dev_info(&pinstance->pdev->dev, 181389a36810SAnil Ravindranath "Host RCB(LDN) failed with IOASC: 0x%08X\n", ioasc); 181489a36810SAnil Ravindranath } 181589a36810SAnil Ravindranath /* send netlink message for HCAM notification if enabled */ 181689a36810SAnil Ravindranath if (!pmcraid_disable_aen) 1817c20c4267SAnil Ravindranath pmcraid_notify_ldn(pinstance); 181889a36810SAnil Ravindranath 181989a36810SAnil Ravindranath cmd = pmcraid_init_hcam(pinstance, PMCRAID_HCAM_CODE_LOG_DATA); 182089a36810SAnil Ravindranath if (cmd) 182189a36810SAnil Ravindranath pmcraid_send_hcam_cmd(cmd); 182289a36810SAnil Ravindranath } 182389a36810SAnil Ravindranath 182489a36810SAnil Ravindranath /** 182589a36810SAnil Ravindranath * pmcraid_register_hcams - register HCAMs for CCN and LDN 182689a36810SAnil Ravindranath * 182789a36810SAnil Ravindranath * @pinstance: pointer per adapter instance structure 182889a36810SAnil Ravindranath * 182989a36810SAnil Ravindranath * Return Value 183089a36810SAnil Ravindranath * none 183189a36810SAnil Ravindranath */ 183289a36810SAnil Ravindranath static void pmcraid_register_hcams(struct pmcraid_instance *pinstance) 183389a36810SAnil Ravindranath { 183489a36810SAnil Ravindranath pmcraid_send_hcam(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE); 183589a36810SAnil Ravindranath pmcraid_send_hcam(pinstance, PMCRAID_HCAM_CODE_LOG_DATA); 183689a36810SAnil Ravindranath } 183789a36810SAnil Ravindranath 183889a36810SAnil Ravindranath /** 183989a36810SAnil Ravindranath * pmcraid_unregister_hcams - cancel HCAMs registered already 184089a36810SAnil Ravindranath * @cmd: pointer to command used as part of reset sequence 184189a36810SAnil Ravindranath */ 184289a36810SAnil Ravindranath static void pmcraid_unregister_hcams(struct pmcraid_cmd *cmd) 184389a36810SAnil Ravindranath { 184489a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 184589a36810SAnil Ravindranath 184689a36810SAnil Ravindranath /* During IOA bringdown, HCAM gets fired and tasklet proceeds with 184789a36810SAnil Ravindranath * handling hcam response though it is not necessary. In order to 184889a36810SAnil Ravindranath * prevent this, set 'ignore', so that bring-down sequence doesn't 184989a36810SAnil Ravindranath * re-send any more hcams 185089a36810SAnil Ravindranath */ 185189a36810SAnil Ravindranath atomic_set(&pinstance->ccn.ignore, 1); 185289a36810SAnil Ravindranath atomic_set(&pinstance->ldn.ignore, 1); 185389a36810SAnil Ravindranath 185489a36810SAnil Ravindranath /* If adapter reset was forced as part of runtime reset sequence, 1855c20c4267SAnil Ravindranath * start the reset sequence. Reset will be triggered even in case 1856c20c4267SAnil Ravindranath * IOA unit_check. 185789a36810SAnil Ravindranath */ 1858c20c4267SAnil Ravindranath if ((pinstance->force_ioa_reset && !pinstance->ioa_bringdown) || 1859c20c4267SAnil Ravindranath pinstance->ioa_unit_check) { 186089a36810SAnil Ravindranath pinstance->force_ioa_reset = 0; 1861c20c4267SAnil Ravindranath pinstance->ioa_unit_check = 0; 186289a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; 186389a36810SAnil Ravindranath pmcraid_reset_alert(cmd); 186489a36810SAnil Ravindranath return; 186589a36810SAnil Ravindranath } 186689a36810SAnil Ravindranath 186789a36810SAnil Ravindranath /* Driver tries to cancel HCAMs by sending ABORT TASK for each HCAM 186889a36810SAnil Ravindranath * one after the other. So CCN cancellation will be triggered by 186989a36810SAnil Ravindranath * pmcraid_cancel_ldn itself. 187089a36810SAnil Ravindranath */ 187189a36810SAnil Ravindranath pmcraid_cancel_ldn(cmd); 187289a36810SAnil Ravindranath } 187389a36810SAnil Ravindranath 18743673b7b0SLee Jones static void pmcraid_reinit_buffers(struct pmcraid_instance *); 18753673b7b0SLee Jones 187689a36810SAnil Ravindranath /** 187789a36810SAnil Ravindranath * pmcraid_reset_enable_ioa - re-enable IOA after a hard reset 187889a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 187989a36810SAnil Ravindranath * Return Value 188089a36810SAnil Ravindranath * 1 if TRANSITION_TO_OPERATIONAL is active, otherwise 0 188189a36810SAnil Ravindranath */ 188289a36810SAnil Ravindranath static int pmcraid_reset_enable_ioa(struct pmcraid_instance *pinstance) 188389a36810SAnil Ravindranath { 188489a36810SAnil Ravindranath u32 intrs; 188589a36810SAnil Ravindranath 188689a36810SAnil Ravindranath pmcraid_reinit_buffers(pinstance); 188789a36810SAnil Ravindranath intrs = pmcraid_read_interrupts(pinstance); 188889a36810SAnil Ravindranath 188989a36810SAnil Ravindranath pmcraid_enable_interrupts(pinstance, PMCRAID_PCI_INTERRUPTS); 189089a36810SAnil Ravindranath 189189a36810SAnil Ravindranath if (intrs & INTRS_TRANSITION_TO_OPERATIONAL) { 1892c20c4267SAnil Ravindranath if (!pinstance->interrupt_mode) { 189389a36810SAnil Ravindranath iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, 1894c20c4267SAnil Ravindranath pinstance->int_regs. 1895c20c4267SAnil Ravindranath ioa_host_interrupt_mask_reg); 189689a36810SAnil Ravindranath iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, 189789a36810SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_clr_reg); 1898c20c4267SAnil Ravindranath } 189989a36810SAnil Ravindranath return 1; 190089a36810SAnil Ravindranath } else { 190189a36810SAnil Ravindranath return 0; 190289a36810SAnil Ravindranath } 190389a36810SAnil Ravindranath } 190489a36810SAnil Ravindranath 190589a36810SAnil Ravindranath /** 190689a36810SAnil Ravindranath * pmcraid_soft_reset - performs a soft reset and makes IOA become ready 190789a36810SAnil Ravindranath * @cmd : pointer to reset command block 190889a36810SAnil Ravindranath * 190989a36810SAnil Ravindranath * Return Value 191089a36810SAnil Ravindranath * none 191189a36810SAnil Ravindranath */ 191289a36810SAnil Ravindranath static void pmcraid_soft_reset(struct pmcraid_cmd *cmd) 191389a36810SAnil Ravindranath { 191489a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 191589a36810SAnil Ravindranath u32 int_reg; 191689a36810SAnil Ravindranath u32 doorbell; 191789a36810SAnil Ravindranath 191889a36810SAnil Ravindranath /* There will be an interrupt when Transition to Operational bit is 191989a36810SAnil Ravindranath * set so tasklet would execute next reset task. The timeout handler 192089a36810SAnil Ravindranath * would re-initiate a reset 192189a36810SAnil Ravindranath */ 192289a36810SAnil Ravindranath cmd->cmd_done = pmcraid_ioa_reset; 192389a36810SAnil Ravindranath cmd->timer.expires = jiffies + 192489a36810SAnil Ravindranath msecs_to_jiffies(PMCRAID_TRANSOP_TIMEOUT); 1925841b86f3SKees Cook cmd->timer.function = pmcraid_timeout_handler; 192689a36810SAnil Ravindranath 192789a36810SAnil Ravindranath if (!timer_pending(&cmd->timer)) 192889a36810SAnil Ravindranath add_timer(&cmd->timer); 192989a36810SAnil Ravindranath 193089a36810SAnil Ravindranath /* Enable destructive diagnostics on IOA if it is not yet in 193189a36810SAnil Ravindranath * operational state 193289a36810SAnil Ravindranath */ 193389a36810SAnil Ravindranath doorbell = DOORBELL_RUNTIME_RESET | 193489a36810SAnil Ravindranath DOORBELL_ENABLE_DESTRUCTIVE_DIAGS; 193589a36810SAnil Ravindranath 1936c20c4267SAnil Ravindranath /* Since we do RESET_ALERT and Start BIST we have to again write 1937c20c4267SAnil Ravindranath * MSIX Doorbell to indicate the interrupt mode 1938c20c4267SAnil Ravindranath */ 1939c20c4267SAnil Ravindranath if (pinstance->interrupt_mode) { 1940c20c4267SAnil Ravindranath iowrite32(DOORBELL_INTR_MODE_MSIX, 1941c20c4267SAnil Ravindranath pinstance->int_regs.host_ioa_interrupt_reg); 1942c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.host_ioa_interrupt_reg); 1943c20c4267SAnil Ravindranath } 1944c20c4267SAnil Ravindranath 194589a36810SAnil Ravindranath iowrite32(doorbell, pinstance->int_regs.host_ioa_interrupt_reg); 1946c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.host_ioa_interrupt_reg), 194789a36810SAnil Ravindranath int_reg = ioread32(pinstance->int_regs.ioa_host_interrupt_reg); 1948c20c4267SAnil Ravindranath 194989a36810SAnil Ravindranath pmcraid_info("Waiting for IOA to become operational %x:%x\n", 195089a36810SAnil Ravindranath ioread32(pinstance->int_regs.host_ioa_interrupt_reg), 195189a36810SAnil Ravindranath int_reg); 195289a36810SAnil Ravindranath } 195389a36810SAnil Ravindranath 195489a36810SAnil Ravindranath /** 195589a36810SAnil Ravindranath * pmcraid_get_dump - retrieves IOA dump in case of Unit Check interrupt 195689a36810SAnil Ravindranath * 195789a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 195889a36810SAnil Ravindranath * 195989a36810SAnil Ravindranath * Return Value 196089a36810SAnil Ravindranath * none 196189a36810SAnil Ravindranath */ 196289a36810SAnil Ravindranath static void pmcraid_get_dump(struct pmcraid_instance *pinstance) 196389a36810SAnil Ravindranath { 196489a36810SAnil Ravindranath pmcraid_info("%s is not yet implemented\n", __func__); 196589a36810SAnil Ravindranath } 196689a36810SAnil Ravindranath 196789a36810SAnil Ravindranath /** 196889a36810SAnil Ravindranath * pmcraid_fail_outstanding_cmds - Fails all outstanding ops. 196989a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 197089a36810SAnil Ravindranath * 197189a36810SAnil Ravindranath * This function fails all outstanding ops. If they are submitted to IOA 197289a36810SAnil Ravindranath * already, it sends cancel all messages if IOA is still accepting IOARCBs, 197389a36810SAnil Ravindranath * otherwise just completes the commands and returns the cmd blocks to free 197489a36810SAnil Ravindranath * pool. 197589a36810SAnil Ravindranath * 197689a36810SAnil Ravindranath * Return value: 197789a36810SAnil Ravindranath * none 197889a36810SAnil Ravindranath */ 197989a36810SAnil Ravindranath static void pmcraid_fail_outstanding_cmds(struct pmcraid_instance *pinstance) 198089a36810SAnil Ravindranath { 198189a36810SAnil Ravindranath struct pmcraid_cmd *cmd, *temp; 198289a36810SAnil Ravindranath unsigned long lock_flags; 198389a36810SAnil Ravindranath 198489a36810SAnil Ravindranath /* pending command list is protected by pending_pool_lock. Its 198589a36810SAnil Ravindranath * traversal must be done as within this lock 198689a36810SAnil Ravindranath */ 198789a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->pending_pool_lock, lock_flags); 198889a36810SAnil Ravindranath list_for_each_entry_safe(cmd, temp, &pinstance->pending_cmd_pool, 198989a36810SAnil Ravindranath free_list) { 199089a36810SAnil Ravindranath list_del(&cmd->free_list); 199189a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->pending_pool_lock, 199289a36810SAnil Ravindranath lock_flags); 199389a36810SAnil Ravindranath cmd->ioa_cb->ioasa.ioasc = 199489a36810SAnil Ravindranath cpu_to_le32(PMCRAID_IOASC_IOA_WAS_RESET); 199589a36810SAnil Ravindranath cmd->ioa_cb->ioasa.ilid = 199645c80be6SArnd Bergmann cpu_to_le32(PMCRAID_DRIVER_ILID); 199789a36810SAnil Ravindranath 199889a36810SAnil Ravindranath /* In case the command timer is still running */ 199989a36810SAnil Ravindranath del_timer(&cmd->timer); 200089a36810SAnil Ravindranath 200189a36810SAnil Ravindranath /* If this is an IO command, complete it by invoking scsi_done 200289a36810SAnil Ravindranath * function. If this is one of the internal commands other 200389a36810SAnil Ravindranath * than pmcraid_ioa_reset and HCAM commands invoke cmd_done to 200489a36810SAnil Ravindranath * complete it 200589a36810SAnil Ravindranath */ 200689a36810SAnil Ravindranath if (cmd->scsi_cmd) { 200789a36810SAnil Ravindranath 200889a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; 200989a36810SAnil Ravindranath __le32 resp = cmd->ioa_cb->ioarcb.response_handle; 201089a36810SAnil Ravindranath 201189a36810SAnil Ravindranath scsi_cmd->result |= DID_ERROR << 16; 201289a36810SAnil Ravindranath 201389a36810SAnil Ravindranath scsi_dma_unmap(scsi_cmd); 201489a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 201589a36810SAnil Ravindranath 201689a36810SAnil Ravindranath pmcraid_info("failing(%d) CDB[0] = %x result: %x\n", 201789a36810SAnil Ravindranath le32_to_cpu(resp) >> 2, 201889a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 201989a36810SAnil Ravindranath scsi_cmd->result); 2020f13cc234SBart Van Assche scsi_done(scsi_cmd); 202189a36810SAnil Ravindranath } else if (cmd->cmd_done == pmcraid_internal_done || 202289a36810SAnil Ravindranath cmd->cmd_done == pmcraid_erp_done) { 202389a36810SAnil Ravindranath cmd->cmd_done(cmd); 2024c20c4267SAnil Ravindranath } else if (cmd->cmd_done != pmcraid_ioa_reset && 2025c20c4267SAnil Ravindranath cmd->cmd_done != pmcraid_ioa_shutdown_done) { 202689a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 202789a36810SAnil Ravindranath } 202889a36810SAnil Ravindranath 202989a36810SAnil Ravindranath atomic_dec(&pinstance->outstanding_cmds); 203089a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->pending_pool_lock, lock_flags); 203189a36810SAnil Ravindranath } 203289a36810SAnil Ravindranath 203389a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->pending_pool_lock, lock_flags); 203489a36810SAnil Ravindranath } 203589a36810SAnil Ravindranath 203689a36810SAnil Ravindranath /** 203789a36810SAnil Ravindranath * pmcraid_ioa_reset - Implementation of IOA reset logic 203889a36810SAnil Ravindranath * 203989a36810SAnil Ravindranath * @cmd: pointer to the cmd block to be used for entire reset process 204089a36810SAnil Ravindranath * 204189a36810SAnil Ravindranath * This function executes most of the steps required for IOA reset. This gets 204289a36810SAnil Ravindranath * called by user threads (modprobe/insmod/rmmod) timer, tasklet and midlayer's 204325985edcSLucas De Marchi * 'eh_' thread. Access to variables used for controlling the reset sequence is 204489a36810SAnil Ravindranath * synchronized using host lock. Various functions called during reset process 204589a36810SAnil Ravindranath * would make use of a single command block, pointer to which is also stored in 204689a36810SAnil Ravindranath * adapter instance structure. 204789a36810SAnil Ravindranath * 204889a36810SAnil Ravindranath * Return Value 204989a36810SAnil Ravindranath * None 205089a36810SAnil Ravindranath */ 205189a36810SAnil Ravindranath static void pmcraid_ioa_reset(struct pmcraid_cmd *cmd) 205289a36810SAnil Ravindranath { 205389a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 205489a36810SAnil Ravindranath u8 reset_complete = 0; 205589a36810SAnil Ravindranath 205689a36810SAnil Ravindranath pinstance->ioa_reset_in_progress = 1; 205789a36810SAnil Ravindranath 205889a36810SAnil Ravindranath if (pinstance->reset_cmd != cmd) { 205989a36810SAnil Ravindranath pmcraid_err("reset is called with different command block\n"); 206089a36810SAnil Ravindranath pinstance->reset_cmd = cmd; 206189a36810SAnil Ravindranath } 206289a36810SAnil Ravindranath 206389a36810SAnil Ravindranath pmcraid_info("reset_engine: state = %d, command = %p\n", 206489a36810SAnil Ravindranath pinstance->ioa_state, cmd); 206589a36810SAnil Ravindranath 206689a36810SAnil Ravindranath switch (pinstance->ioa_state) { 206789a36810SAnil Ravindranath 206889a36810SAnil Ravindranath case IOA_STATE_DEAD: 206989a36810SAnil Ravindranath /* If IOA is offline, whatever may be the reset reason, just 207089a36810SAnil Ravindranath * return. callers might be waiting on the reset wait_q, wake 207189a36810SAnil Ravindranath * up them 207289a36810SAnil Ravindranath */ 207389a36810SAnil Ravindranath pmcraid_err("IOA is offline no reset is possible\n"); 207489a36810SAnil Ravindranath reset_complete = 1; 207589a36810SAnil Ravindranath break; 207689a36810SAnil Ravindranath 207789a36810SAnil Ravindranath case IOA_STATE_IN_BRINGDOWN: 207889a36810SAnil Ravindranath /* we enter here, once ioa shutdown command is processed by IOA 207989a36810SAnil Ravindranath * Alert IOA for a possible reset. If reset alert fails, IOA 208089a36810SAnil Ravindranath * goes through hard-reset 208189a36810SAnil Ravindranath */ 208289a36810SAnil Ravindranath pmcraid_disable_interrupts(pinstance, ~0); 208389a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; 208489a36810SAnil Ravindranath pmcraid_reset_alert(cmd); 208589a36810SAnil Ravindranath break; 208689a36810SAnil Ravindranath 208789a36810SAnil Ravindranath case IOA_STATE_UNKNOWN: 208889a36810SAnil Ravindranath /* We may be called during probe or resume. Some pre-processing 208989a36810SAnil Ravindranath * is required for prior to reset 209089a36810SAnil Ravindranath */ 209189a36810SAnil Ravindranath scsi_block_requests(pinstance->host); 209289a36810SAnil Ravindranath 209389a36810SAnil Ravindranath /* If asked to reset while IOA was processing responses or 209489a36810SAnil Ravindranath * there are any error responses then IOA may require 209589a36810SAnil Ravindranath * hard-reset. 209689a36810SAnil Ravindranath */ 209789a36810SAnil Ravindranath if (pinstance->ioa_hard_reset == 0) { 209889a36810SAnil Ravindranath if (ioread32(pinstance->ioa_status) & 209989a36810SAnil Ravindranath INTRS_TRANSITION_TO_OPERATIONAL) { 210089a36810SAnil Ravindranath pmcraid_info("sticky bit set, bring-up\n"); 210189a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_BRINGUP; 210289a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 210389a36810SAnil Ravindranath pmcraid_identify_hrrq(cmd); 210489a36810SAnil Ravindranath } else { 210589a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_SOFT_RESET; 210689a36810SAnil Ravindranath pmcraid_soft_reset(cmd); 210789a36810SAnil Ravindranath } 210889a36810SAnil Ravindranath } else { 210989a36810SAnil Ravindranath /* Alert IOA of a possible reset and wait for critical 211089a36810SAnil Ravindranath * operation in progress bit to reset 211189a36810SAnil Ravindranath */ 211289a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; 211389a36810SAnil Ravindranath pmcraid_reset_alert(cmd); 211489a36810SAnil Ravindranath } 211589a36810SAnil Ravindranath break; 211689a36810SAnil Ravindranath 211789a36810SAnil Ravindranath case IOA_STATE_IN_RESET_ALERT: 211889a36810SAnil Ravindranath /* If critical operation in progress bit is reset or wait gets 211989a36810SAnil Ravindranath * timed out, reset proceeds with starting BIST on the IOA. 212089a36810SAnil Ravindranath * pmcraid_ioa_hard_reset keeps a count of reset attempts. If 212189a36810SAnil Ravindranath * they are 3 or more, reset engine marks IOA dead and returns 212289a36810SAnil Ravindranath */ 212389a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_HARD_RESET; 212489a36810SAnil Ravindranath pmcraid_start_bist(cmd); 212589a36810SAnil Ravindranath break; 212689a36810SAnil Ravindranath 212789a36810SAnil Ravindranath case IOA_STATE_IN_HARD_RESET: 212889a36810SAnil Ravindranath pinstance->ioa_reset_attempts++; 212989a36810SAnil Ravindranath 213089a36810SAnil Ravindranath /* retry reset if we haven't reached maximum allowed limit */ 213189a36810SAnil Ravindranath if (pinstance->ioa_reset_attempts > PMCRAID_RESET_ATTEMPTS) { 213289a36810SAnil Ravindranath pinstance->ioa_reset_attempts = 0; 213389a36810SAnil Ravindranath pmcraid_err("IOA didn't respond marking it as dead\n"); 213489a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_DEAD; 2135c20c4267SAnil Ravindranath 2136c20c4267SAnil Ravindranath if (pinstance->ioa_bringdown) 2137c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, 2138c20c4267SAnil Ravindranath PMC_DEVICE_EVENT_SHUTDOWN_FAILED); 2139c20c4267SAnil Ravindranath else 2140c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, 2141c20c4267SAnil Ravindranath PMC_DEVICE_EVENT_RESET_FAILED); 214289a36810SAnil Ravindranath reset_complete = 1; 214389a36810SAnil Ravindranath break; 214489a36810SAnil Ravindranath } 214589a36810SAnil Ravindranath 214689a36810SAnil Ravindranath /* Once either bist or pci reset is done, restore PCI config 214789a36810SAnil Ravindranath * space. If this fails, proceed with hard reset again 214889a36810SAnil Ravindranath */ 21491d3c16a8SJon Mason pci_restore_state(pinstance->pdev); 215089a36810SAnil Ravindranath 215189a36810SAnil Ravindranath /* fail all pending commands */ 215289a36810SAnil Ravindranath pmcraid_fail_outstanding_cmds(pinstance); 215389a36810SAnil Ravindranath 215489a36810SAnil Ravindranath /* check if unit check is active, if so extract dump */ 215589a36810SAnil Ravindranath if (pinstance->ioa_unit_check) { 215689a36810SAnil Ravindranath pmcraid_info("unit check is active\n"); 215789a36810SAnil Ravindranath pinstance->ioa_unit_check = 0; 215889a36810SAnil Ravindranath pmcraid_get_dump(pinstance); 215989a36810SAnil Ravindranath pinstance->ioa_reset_attempts--; 216089a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; 216189a36810SAnil Ravindranath pmcraid_reset_alert(cmd); 216289a36810SAnil Ravindranath break; 216389a36810SAnil Ravindranath } 216489a36810SAnil Ravindranath 216589a36810SAnil Ravindranath /* if the reset reason is to bring-down the ioa, we might be 216689a36810SAnil Ravindranath * done with the reset restore pci_config_space and complete 216789a36810SAnil Ravindranath * the reset 216889a36810SAnil Ravindranath */ 216989a36810SAnil Ravindranath if (pinstance->ioa_bringdown) { 217089a36810SAnil Ravindranath pmcraid_info("bringing down the adapter\n"); 217189a36810SAnil Ravindranath pinstance->ioa_shutdown_type = SHUTDOWN_NONE; 217289a36810SAnil Ravindranath pinstance->ioa_bringdown = 0; 217389a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_UNKNOWN; 2174c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, 2175c20c4267SAnil Ravindranath PMC_DEVICE_EVENT_SHUTDOWN_SUCCESS); 217689a36810SAnil Ravindranath reset_complete = 1; 217789a36810SAnil Ravindranath } else { 217889a36810SAnil Ravindranath /* bring-up IOA, so proceed with soft reset 217989a36810SAnil Ravindranath * Reinitialize hrrq_buffers and their indices also 218089a36810SAnil Ravindranath * enable interrupts after a pci_restore_state 218189a36810SAnil Ravindranath */ 218289a36810SAnil Ravindranath if (pmcraid_reset_enable_ioa(pinstance)) { 218389a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_BRINGUP; 218489a36810SAnil Ravindranath pmcraid_info("bringing up the adapter\n"); 218589a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 218689a36810SAnil Ravindranath pmcraid_identify_hrrq(cmd); 218789a36810SAnil Ravindranath } else { 218889a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_SOFT_RESET; 218989a36810SAnil Ravindranath pmcraid_soft_reset(cmd); 219089a36810SAnil Ravindranath } 219189a36810SAnil Ravindranath } 219289a36810SAnil Ravindranath break; 219389a36810SAnil Ravindranath 219489a36810SAnil Ravindranath case IOA_STATE_IN_SOFT_RESET: 219589a36810SAnil Ravindranath /* TRANSITION TO OPERATIONAL is on so start initialization 219689a36810SAnil Ravindranath * sequence 219789a36810SAnil Ravindranath */ 219889a36810SAnil Ravindranath pmcraid_info("In softreset proceeding with bring-up\n"); 219989a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_BRINGUP; 220089a36810SAnil Ravindranath 220189a36810SAnil Ravindranath /* Initialization commands start with HRRQ identification. From 220289a36810SAnil Ravindranath * now on tasklet completes most of the commands as IOA is up 220389a36810SAnil Ravindranath * and intrs are enabled 220489a36810SAnil Ravindranath */ 220589a36810SAnil Ravindranath pmcraid_identify_hrrq(cmd); 220689a36810SAnil Ravindranath break; 220789a36810SAnil Ravindranath 220889a36810SAnil Ravindranath case IOA_STATE_IN_BRINGUP: 220989a36810SAnil Ravindranath /* we are done with bringing up of IOA, change the ioa_state to 221089a36810SAnil Ravindranath * operational and wake up any waiters 221189a36810SAnil Ravindranath */ 221289a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_OPERATIONAL; 221389a36810SAnil Ravindranath reset_complete = 1; 221489a36810SAnil Ravindranath break; 221589a36810SAnil Ravindranath 221689a36810SAnil Ravindranath case IOA_STATE_OPERATIONAL: 221789a36810SAnil Ravindranath default: 221889a36810SAnil Ravindranath /* When IOA is operational and a reset is requested, check for 221989a36810SAnil Ravindranath * the reset reason. If reset is to bring down IOA, unregister 222089a36810SAnil Ravindranath * HCAMs and initiate shutdown; if adapter reset is forced then 222189a36810SAnil Ravindranath * restart reset sequence again 222289a36810SAnil Ravindranath */ 222389a36810SAnil Ravindranath if (pinstance->ioa_shutdown_type == SHUTDOWN_NONE && 222489a36810SAnil Ravindranath pinstance->force_ioa_reset == 0) { 2225c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, 2226c20c4267SAnil Ravindranath PMC_DEVICE_EVENT_RESET_SUCCESS); 222789a36810SAnil Ravindranath reset_complete = 1; 222889a36810SAnil Ravindranath } else { 222989a36810SAnil Ravindranath if (pinstance->ioa_shutdown_type != SHUTDOWN_NONE) 223089a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_IN_BRINGDOWN; 223189a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 223289a36810SAnil Ravindranath pmcraid_unregister_hcams(cmd); 223389a36810SAnil Ravindranath } 223489a36810SAnil Ravindranath break; 223589a36810SAnil Ravindranath } 223689a36810SAnil Ravindranath 223789a36810SAnil Ravindranath /* reset will be completed if ioa_state is either DEAD or UNKNOWN or 223889a36810SAnil Ravindranath * OPERATIONAL. Reset all control variables used during reset, wake up 223989a36810SAnil Ravindranath * any waiting threads and let the SCSI mid-layer send commands. Note 224089a36810SAnil Ravindranath * that host_lock must be held before invoking scsi_report_bus_reset. 224189a36810SAnil Ravindranath */ 224289a36810SAnil Ravindranath if (reset_complete) { 224389a36810SAnil Ravindranath pinstance->ioa_reset_in_progress = 0; 224489a36810SAnil Ravindranath pinstance->ioa_reset_attempts = 0; 224589a36810SAnil Ravindranath pinstance->reset_cmd = NULL; 224689a36810SAnil Ravindranath pinstance->ioa_shutdown_type = SHUTDOWN_NONE; 224789a36810SAnil Ravindranath pinstance->ioa_bringdown = 0; 224889a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 224989a36810SAnil Ravindranath 225089a36810SAnil Ravindranath /* If target state is to bring up the adapter, proceed with 225189a36810SAnil Ravindranath * hcam registration and resource exposure to mid-layer. 225289a36810SAnil Ravindranath */ 225389a36810SAnil Ravindranath if (pinstance->ioa_state == IOA_STATE_OPERATIONAL) 225489a36810SAnil Ravindranath pmcraid_register_hcams(pinstance); 225589a36810SAnil Ravindranath 225689a36810SAnil Ravindranath wake_up_all(&pinstance->reset_wait_q); 225789a36810SAnil Ravindranath } 225889a36810SAnil Ravindranath 225989a36810SAnil Ravindranath return; 226089a36810SAnil Ravindranath } 226189a36810SAnil Ravindranath 226289a36810SAnil Ravindranath /** 226389a36810SAnil Ravindranath * pmcraid_initiate_reset - initiates reset sequence. This is called from 226489a36810SAnil Ravindranath * ISR/tasklet during error interrupts including IOA unit check. If reset 226589a36810SAnil Ravindranath * is already in progress, it just returns, otherwise initiates IOA reset 226689a36810SAnil Ravindranath * to bring IOA up to operational state. 226789a36810SAnil Ravindranath * 226889a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 226989a36810SAnil Ravindranath * 227089a36810SAnil Ravindranath * Return value 227189a36810SAnil Ravindranath * none 227289a36810SAnil Ravindranath */ 227389a36810SAnil Ravindranath static void pmcraid_initiate_reset(struct pmcraid_instance *pinstance) 227489a36810SAnil Ravindranath { 227589a36810SAnil Ravindranath struct pmcraid_cmd *cmd; 227689a36810SAnil Ravindranath 227789a36810SAnil Ravindranath /* If the reset is already in progress, just return, otherwise start 227889a36810SAnil Ravindranath * reset sequence and return 227989a36810SAnil Ravindranath */ 228089a36810SAnil Ravindranath if (!pinstance->ioa_reset_in_progress) { 228189a36810SAnil Ravindranath scsi_block_requests(pinstance->host); 228289a36810SAnil Ravindranath cmd = pmcraid_get_free_cmd(pinstance); 228389a36810SAnil Ravindranath 228489a36810SAnil Ravindranath if (cmd == NULL) { 228589a36810SAnil Ravindranath pmcraid_err("no cmnd blocks for initiate_reset\n"); 228689a36810SAnil Ravindranath return; 228789a36810SAnil Ravindranath } 228889a36810SAnil Ravindranath 228989a36810SAnil Ravindranath pinstance->ioa_shutdown_type = SHUTDOWN_NONE; 229089a36810SAnil Ravindranath pinstance->reset_cmd = cmd; 229189a36810SAnil Ravindranath pinstance->force_ioa_reset = 1; 2292c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, 2293c20c4267SAnil Ravindranath PMC_DEVICE_EVENT_RESET_START); 229489a36810SAnil Ravindranath pmcraid_ioa_reset(cmd); 229589a36810SAnil Ravindranath } 229689a36810SAnil Ravindranath } 229789a36810SAnil Ravindranath 229889a36810SAnil Ravindranath /** 229989a36810SAnil Ravindranath * pmcraid_reset_reload - utility routine for doing IOA reset either to bringup 230089a36810SAnil Ravindranath * or bringdown IOA 230189a36810SAnil Ravindranath * @pinstance: pointer adapter instance structure 230289a36810SAnil Ravindranath * @shutdown_type: shutdown type to be used NONE, NORMAL or ABRREV 230389a36810SAnil Ravindranath * @target_state: expected target state after reset 230489a36810SAnil Ravindranath * 230589a36810SAnil Ravindranath * Note: This command initiates reset and waits for its completion. Hence this 230689a36810SAnil Ravindranath * should not be called from isr/timer/tasklet functions (timeout handlers, 230789a36810SAnil Ravindranath * error response handlers and interrupt handlers). 230889a36810SAnil Ravindranath * 230989a36810SAnil Ravindranath * Return Value 231089a36810SAnil Ravindranath * 1 in case ioa_state is not target_state, 0 otherwise. 231189a36810SAnil Ravindranath */ 231289a36810SAnil Ravindranath static int pmcraid_reset_reload( 231389a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 231489a36810SAnil Ravindranath u8 shutdown_type, 231589a36810SAnil Ravindranath u8 target_state 231689a36810SAnil Ravindranath ) 231789a36810SAnil Ravindranath { 231889a36810SAnil Ravindranath struct pmcraid_cmd *reset_cmd = NULL; 231989a36810SAnil Ravindranath unsigned long lock_flags; 232089a36810SAnil Ravindranath int reset = 1; 232189a36810SAnil Ravindranath 232289a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 232389a36810SAnil Ravindranath 232489a36810SAnil Ravindranath if (pinstance->ioa_reset_in_progress) { 232589a36810SAnil Ravindranath pmcraid_info("reset_reload: reset is already in progress\n"); 232689a36810SAnil Ravindranath 232789a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 232889a36810SAnil Ravindranath 232989a36810SAnil Ravindranath wait_event(pinstance->reset_wait_q, 233089a36810SAnil Ravindranath !pinstance->ioa_reset_in_progress); 233189a36810SAnil Ravindranath 233289a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 233389a36810SAnil Ravindranath 233489a36810SAnil Ravindranath if (pinstance->ioa_state == IOA_STATE_DEAD) { 233589a36810SAnil Ravindranath pmcraid_info("reset_reload: IOA is dead\n"); 233691402608SChristoph Hellwig goto out_unlock; 233791402608SChristoph Hellwig } 233891402608SChristoph Hellwig 233991402608SChristoph Hellwig if (pinstance->ioa_state == target_state) { 234089a36810SAnil Ravindranath reset = 0; 234191402608SChristoph Hellwig goto out_unlock; 234289a36810SAnil Ravindranath } 234389a36810SAnil Ravindranath } 234489a36810SAnil Ravindranath 234589a36810SAnil Ravindranath pmcraid_info("reset_reload: proceeding with reset\n"); 234689a36810SAnil Ravindranath scsi_block_requests(pinstance->host); 234789a36810SAnil Ravindranath reset_cmd = pmcraid_get_free_cmd(pinstance); 234889a36810SAnil Ravindranath if (reset_cmd == NULL) { 234989a36810SAnil Ravindranath pmcraid_err("no free cmnd for reset_reload\n"); 235091402608SChristoph Hellwig goto out_unlock; 235189a36810SAnil Ravindranath } 235289a36810SAnil Ravindranath 235389a36810SAnil Ravindranath if (shutdown_type == SHUTDOWN_NORMAL) 235489a36810SAnil Ravindranath pinstance->ioa_bringdown = 1; 235589a36810SAnil Ravindranath 235689a36810SAnil Ravindranath pinstance->ioa_shutdown_type = shutdown_type; 235789a36810SAnil Ravindranath pinstance->reset_cmd = reset_cmd; 235889a36810SAnil Ravindranath pinstance->force_ioa_reset = reset; 235989a36810SAnil Ravindranath pmcraid_info("reset_reload: initiating reset\n"); 236089a36810SAnil Ravindranath pmcraid_ioa_reset(reset_cmd); 236189a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 236289a36810SAnil Ravindranath pmcraid_info("reset_reload: waiting for reset to complete\n"); 236389a36810SAnil Ravindranath wait_event(pinstance->reset_wait_q, 236489a36810SAnil Ravindranath !pinstance->ioa_reset_in_progress); 236589a36810SAnil Ravindranath 236689a36810SAnil Ravindranath pmcraid_info("reset_reload: reset is complete !!\n"); 236789a36810SAnil Ravindranath scsi_unblock_requests(pinstance->host); 236891402608SChristoph Hellwig return pinstance->ioa_state != target_state; 236989a36810SAnil Ravindranath 237091402608SChristoph Hellwig out_unlock: 237191402608SChristoph Hellwig spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 237289a36810SAnil Ravindranath return reset; 237389a36810SAnil Ravindranath } 237489a36810SAnil Ravindranath 237589a36810SAnil Ravindranath /** 237689a36810SAnil Ravindranath * pmcraid_reset_bringdown - wrapper over pmcraid_reset_reload to bringdown IOA 237789a36810SAnil Ravindranath * 237889a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 237989a36810SAnil Ravindranath * 238089a36810SAnil Ravindranath * Return Value 238189a36810SAnil Ravindranath * whatever is returned from pmcraid_reset_reload 238289a36810SAnil Ravindranath */ 238389a36810SAnil Ravindranath static int pmcraid_reset_bringdown(struct pmcraid_instance *pinstance) 238489a36810SAnil Ravindranath { 238589a36810SAnil Ravindranath return pmcraid_reset_reload(pinstance, 238689a36810SAnil Ravindranath SHUTDOWN_NORMAL, 238789a36810SAnil Ravindranath IOA_STATE_UNKNOWN); 238889a36810SAnil Ravindranath } 238989a36810SAnil Ravindranath 239089a36810SAnil Ravindranath /** 239189a36810SAnil Ravindranath * pmcraid_reset_bringup - wrapper over pmcraid_reset_reload to bring up IOA 239289a36810SAnil Ravindranath * 239389a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 239489a36810SAnil Ravindranath * 239589a36810SAnil Ravindranath * Return Value 239689a36810SAnil Ravindranath * whatever is returned from pmcraid_reset_reload 239789a36810SAnil Ravindranath */ 239889a36810SAnil Ravindranath static int pmcraid_reset_bringup(struct pmcraid_instance *pinstance) 239989a36810SAnil Ravindranath { 2400c20c4267SAnil Ravindranath pmcraid_notify_ioastate(pinstance, PMC_DEVICE_EVENT_RESET_START); 2401c20c4267SAnil Ravindranath 240289a36810SAnil Ravindranath return pmcraid_reset_reload(pinstance, 240389a36810SAnil Ravindranath SHUTDOWN_NONE, 240489a36810SAnil Ravindranath IOA_STATE_OPERATIONAL); 240589a36810SAnil Ravindranath } 240689a36810SAnil Ravindranath 240789a36810SAnil Ravindranath /** 240889a36810SAnil Ravindranath * pmcraid_request_sense - Send request sense to a device 240989a36810SAnil Ravindranath * @cmd: pmcraid command struct 241089a36810SAnil Ravindranath * 241189a36810SAnil Ravindranath * This function sends a request sense to a device as a result of a check 241289a36810SAnil Ravindranath * condition. This method re-uses the same command block that failed earlier. 241389a36810SAnil Ravindranath */ 241489a36810SAnil Ravindranath static void pmcraid_request_sense(struct pmcraid_cmd *cmd) 241589a36810SAnil Ravindranath { 241689a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 241789a36810SAnil Ravindranath struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; 2418a9b9e3adSChristoph Hellwig struct device *dev = &cmd->drv_inst->pdev->dev; 241989a36810SAnil Ravindranath 2420a9b9e3adSChristoph Hellwig cmd->sense_buffer = cmd->scsi_cmd->sense_buffer; 2421a9b9e3adSChristoph Hellwig cmd->sense_buffer_dma = dma_map_single(dev, cmd->sense_buffer, 2422a9b9e3adSChristoph Hellwig SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); 2423a9b9e3adSChristoph Hellwig if (dma_mapping_error(dev, cmd->sense_buffer_dma)) { 242489a36810SAnil Ravindranath pmcraid_err 242589a36810SAnil Ravindranath ("couldn't allocate sense buffer for request sense\n"); 242689a36810SAnil Ravindranath pmcraid_erp_done(cmd); 242789a36810SAnil Ravindranath return; 242889a36810SAnil Ravindranath } 242989a36810SAnil Ravindranath 243089a36810SAnil Ravindranath /* re-use the command block */ 243189a36810SAnil Ravindranath memset(&cmd->ioa_cb->ioasa, 0, sizeof(struct pmcraid_ioasa)); 243289a36810SAnil Ravindranath memset(ioarcb->cdb, 0, PMCRAID_MAX_CDB_LEN); 243389a36810SAnil Ravindranath ioarcb->request_flags0 = (SYNC_COMPLETE | 243489a36810SAnil Ravindranath NO_LINK_DESCS | 243589a36810SAnil Ravindranath INHIBIT_UL_CHECK); 243689a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_SCSI; 243789a36810SAnil Ravindranath ioarcb->cdb[0] = REQUEST_SENSE; 243889a36810SAnil Ravindranath ioarcb->cdb[4] = SCSI_SENSE_BUFFERSIZE; 243989a36810SAnil Ravindranath 244089a36810SAnil Ravindranath ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + 244189a36810SAnil Ravindranath offsetof(struct pmcraid_ioarcb, 244289a36810SAnil Ravindranath add_data.u.ioadl[0])); 244389a36810SAnil Ravindranath ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); 244489a36810SAnil Ravindranath 244589a36810SAnil Ravindranath ioarcb->data_transfer_length = cpu_to_le32(SCSI_SENSE_BUFFERSIZE); 244689a36810SAnil Ravindranath 244789a36810SAnil Ravindranath ioadl->address = cpu_to_le64(cmd->sense_buffer_dma); 244889a36810SAnil Ravindranath ioadl->data_len = cpu_to_le32(SCSI_SENSE_BUFFERSIZE); 244988197966SAnil Ravindranath ioadl->flags = IOADL_FLAGS_LAST_DESC; 245089a36810SAnil Ravindranath 245189a36810SAnil Ravindranath /* request sense might be called as part of error response processing 245289a36810SAnil Ravindranath * which runs in tasklets context. It is possible that mid-layer might 245389a36810SAnil Ravindranath * schedule queuecommand during this time, hence, writting to IOARRIN 245489a36810SAnil Ravindranath * must be protect by host_lock 245589a36810SAnil Ravindranath */ 245689a36810SAnil Ravindranath pmcraid_send_cmd(cmd, pmcraid_erp_done, 245789a36810SAnil Ravindranath PMCRAID_REQUEST_SENSE_TIMEOUT, 245889a36810SAnil Ravindranath pmcraid_timeout_handler); 245989a36810SAnil Ravindranath } 246089a36810SAnil Ravindranath 246189a36810SAnil Ravindranath /** 246289a36810SAnil Ravindranath * pmcraid_cancel_all - cancel all outstanding IOARCBs as part of error recovery 246389a36810SAnil Ravindranath * @cmd: command that failed 2464203654b4SChristoph Hellwig * @need_sense: true if request_sense is required after cancel all 246589a36810SAnil Ravindranath * 246689a36810SAnil Ravindranath * This function sends a cancel all to a device to clear the queue. 246789a36810SAnil Ravindranath */ 2468203654b4SChristoph Hellwig static void pmcraid_cancel_all(struct pmcraid_cmd *cmd, bool need_sense) 246989a36810SAnil Ravindranath { 247089a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; 247189a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 247289a36810SAnil Ravindranath struct pmcraid_resource_entry *res = scsi_cmd->device->hostdata; 247389a36810SAnil Ravindranath 247489a36810SAnil Ravindranath memset(ioarcb->cdb, 0, PMCRAID_MAX_CDB_LEN); 247589a36810SAnil Ravindranath ioarcb->request_flags0 = SYNC_OVERRIDE; 247689a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_IOACMD; 247789a36810SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_CANCEL_ALL_REQUESTS; 247889a36810SAnil Ravindranath 247989a36810SAnil Ravindranath if (RES_IS_GSCSI(res->cfg_entry)) 248089a36810SAnil Ravindranath ioarcb->cdb[1] = PMCRAID_SYNC_COMPLETE_AFTER_CANCEL; 248189a36810SAnil Ravindranath 248289a36810SAnil Ravindranath ioarcb->ioadl_bus_addr = 0; 248389a36810SAnil Ravindranath ioarcb->ioadl_length = 0; 248489a36810SAnil Ravindranath ioarcb->data_transfer_length = 0; 248545c80be6SArnd Bergmann ioarcb->ioarcb_bus_addr &= cpu_to_le64((~0x1FULL)); 248689a36810SAnil Ravindranath 248789a36810SAnil Ravindranath /* writing to IOARRIN must be protected by host_lock, as mid-layer 248889a36810SAnil Ravindranath * schedule queuecommand while we are doing this 248989a36810SAnil Ravindranath */ 2490203654b4SChristoph Hellwig pmcraid_send_cmd(cmd, need_sense ? 2491203654b4SChristoph Hellwig pmcraid_erp_done : pmcraid_request_sense, 249289a36810SAnil Ravindranath PMCRAID_REQUEST_SENSE_TIMEOUT, 249389a36810SAnil Ravindranath pmcraid_timeout_handler); 249489a36810SAnil Ravindranath } 249589a36810SAnil Ravindranath 249689a36810SAnil Ravindranath /** 249789a36810SAnil Ravindranath * pmcraid_frame_auto_sense: frame fixed format sense information 249889a36810SAnil Ravindranath * 249989a36810SAnil Ravindranath * @cmd: pointer to failing command block 250089a36810SAnil Ravindranath * 250189a36810SAnil Ravindranath * Return value 250289a36810SAnil Ravindranath * none 250389a36810SAnil Ravindranath */ 250489a36810SAnil Ravindranath static void pmcraid_frame_auto_sense(struct pmcraid_cmd *cmd) 250589a36810SAnil Ravindranath { 250689a36810SAnil Ravindranath u8 *sense_buf = cmd->scsi_cmd->sense_buffer; 250789a36810SAnil Ravindranath struct pmcraid_resource_entry *res = cmd->scsi_cmd->device->hostdata; 250889a36810SAnil Ravindranath struct pmcraid_ioasa *ioasa = &cmd->ioa_cb->ioasa; 250989a36810SAnil Ravindranath u32 ioasc = le32_to_cpu(ioasa->ioasc); 251089a36810SAnil Ravindranath u32 failing_lba = 0; 251189a36810SAnil Ravindranath 251289a36810SAnil Ravindranath memset(sense_buf, 0, SCSI_SENSE_BUFFERSIZE); 251389a36810SAnil Ravindranath cmd->scsi_cmd->result = SAM_STAT_CHECK_CONDITION; 251489a36810SAnil Ravindranath 251589a36810SAnil Ravindranath if (RES_IS_VSET(res->cfg_entry) && 251689a36810SAnil Ravindranath ioasc == PMCRAID_IOASC_ME_READ_ERROR_NO_REALLOC && 251789a36810SAnil Ravindranath ioasa->u.vset.failing_lba_hi != 0) { 251889a36810SAnil Ravindranath 251989a36810SAnil Ravindranath sense_buf[0] = 0x72; 252089a36810SAnil Ravindranath sense_buf[1] = PMCRAID_IOASC_SENSE_KEY(ioasc); 252189a36810SAnil Ravindranath sense_buf[2] = PMCRAID_IOASC_SENSE_CODE(ioasc); 252289a36810SAnil Ravindranath sense_buf[3] = PMCRAID_IOASC_SENSE_QUAL(ioasc); 252389a36810SAnil Ravindranath 252489a36810SAnil Ravindranath sense_buf[7] = 12; 252589a36810SAnil Ravindranath sense_buf[8] = 0; 252689a36810SAnil Ravindranath sense_buf[9] = 0x0A; 252789a36810SAnil Ravindranath sense_buf[10] = 0x80; 252889a36810SAnil Ravindranath 252989a36810SAnil Ravindranath failing_lba = le32_to_cpu(ioasa->u.vset.failing_lba_hi); 253089a36810SAnil Ravindranath 253189a36810SAnil Ravindranath sense_buf[12] = (failing_lba & 0xff000000) >> 24; 253289a36810SAnil Ravindranath sense_buf[13] = (failing_lba & 0x00ff0000) >> 16; 253389a36810SAnil Ravindranath sense_buf[14] = (failing_lba & 0x0000ff00) >> 8; 253489a36810SAnil Ravindranath sense_buf[15] = failing_lba & 0x000000ff; 253589a36810SAnil Ravindranath 253689a36810SAnil Ravindranath failing_lba = le32_to_cpu(ioasa->u.vset.failing_lba_lo); 253789a36810SAnil Ravindranath 253889a36810SAnil Ravindranath sense_buf[16] = (failing_lba & 0xff000000) >> 24; 253989a36810SAnil Ravindranath sense_buf[17] = (failing_lba & 0x00ff0000) >> 16; 254089a36810SAnil Ravindranath sense_buf[18] = (failing_lba & 0x0000ff00) >> 8; 254189a36810SAnil Ravindranath sense_buf[19] = failing_lba & 0x000000ff; 254289a36810SAnil Ravindranath } else { 254389a36810SAnil Ravindranath sense_buf[0] = 0x70; 254489a36810SAnil Ravindranath sense_buf[2] = PMCRAID_IOASC_SENSE_KEY(ioasc); 254589a36810SAnil Ravindranath sense_buf[12] = PMCRAID_IOASC_SENSE_CODE(ioasc); 254689a36810SAnil Ravindranath sense_buf[13] = PMCRAID_IOASC_SENSE_QUAL(ioasc); 254789a36810SAnil Ravindranath 254889a36810SAnil Ravindranath if (ioasc == PMCRAID_IOASC_ME_READ_ERROR_NO_REALLOC) { 254989a36810SAnil Ravindranath if (RES_IS_VSET(res->cfg_entry)) 255089a36810SAnil Ravindranath failing_lba = 255189a36810SAnil Ravindranath le32_to_cpu(ioasa->u. 255289a36810SAnil Ravindranath vset.failing_lba_lo); 255389a36810SAnil Ravindranath sense_buf[0] |= 0x80; 255489a36810SAnil Ravindranath sense_buf[3] = (failing_lba >> 24) & 0xff; 255589a36810SAnil Ravindranath sense_buf[4] = (failing_lba >> 16) & 0xff; 255689a36810SAnil Ravindranath sense_buf[5] = (failing_lba >> 8) & 0xff; 255789a36810SAnil Ravindranath sense_buf[6] = failing_lba & 0xff; 255889a36810SAnil Ravindranath } 255989a36810SAnil Ravindranath 256089a36810SAnil Ravindranath sense_buf[7] = 6; /* additional length */ 256189a36810SAnil Ravindranath } 256289a36810SAnil Ravindranath } 256389a36810SAnil Ravindranath 256489a36810SAnil Ravindranath /** 256589a36810SAnil Ravindranath * pmcraid_error_handler - Error response handlers for a SCSI op 256689a36810SAnil Ravindranath * @cmd: pointer to pmcraid_cmd that has failed 256789a36810SAnil Ravindranath * 256889a36810SAnil Ravindranath * This function determines whether or not to initiate ERP on the affected 256989a36810SAnil Ravindranath * device. This is called from a tasklet, which doesn't hold any locks. 257089a36810SAnil Ravindranath * 257189a36810SAnil Ravindranath * Return value: 257289a36810SAnil Ravindranath * 0 it caller can complete the request, otherwise 1 where in error 257389a36810SAnil Ravindranath * handler itself completes the request and returns the command block 257489a36810SAnil Ravindranath * back to free-pool 257589a36810SAnil Ravindranath */ 257689a36810SAnil Ravindranath static int pmcraid_error_handler(struct pmcraid_cmd *cmd) 257789a36810SAnil Ravindranath { 257889a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; 257989a36810SAnil Ravindranath struct pmcraid_resource_entry *res = scsi_cmd->device->hostdata; 258089a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 258189a36810SAnil Ravindranath struct pmcraid_ioasa *ioasa = &cmd->ioa_cb->ioasa; 258289a36810SAnil Ravindranath u32 ioasc = le32_to_cpu(ioasa->ioasc); 258389a36810SAnil Ravindranath u32 masked_ioasc = ioasc & PMCRAID_IOASC_SENSE_MASK; 2584203654b4SChristoph Hellwig bool sense_copied = false; 258589a36810SAnil Ravindranath 258689a36810SAnil Ravindranath if (!res) { 258789a36810SAnil Ravindranath pmcraid_info("resource pointer is NULL\n"); 258889a36810SAnil Ravindranath return 0; 258989a36810SAnil Ravindranath } 259089a36810SAnil Ravindranath 259189a36810SAnil Ravindranath /* If this was a SCSI read/write command keep count of errors */ 259289a36810SAnil Ravindranath if (SCSI_CMD_TYPE(scsi_cmd->cmnd[0]) == SCSI_READ_CMD) 259389a36810SAnil Ravindranath atomic_inc(&res->read_failures); 259489a36810SAnil Ravindranath else if (SCSI_CMD_TYPE(scsi_cmd->cmnd[0]) == SCSI_WRITE_CMD) 259589a36810SAnil Ravindranath atomic_inc(&res->write_failures); 259689a36810SAnil Ravindranath 259789a36810SAnil Ravindranath if (!RES_IS_GSCSI(res->cfg_entry) && 259889a36810SAnil Ravindranath masked_ioasc != PMCRAID_IOASC_HW_DEVICE_BUS_STATUS_ERROR) { 259989a36810SAnil Ravindranath pmcraid_frame_auto_sense(cmd); 260089a36810SAnil Ravindranath } 260189a36810SAnil Ravindranath 260289a36810SAnil Ravindranath /* Log IOASC/IOASA information based on user settings */ 260389a36810SAnil Ravindranath pmcraid_ioasc_logger(ioasc, cmd); 260489a36810SAnil Ravindranath 260589a36810SAnil Ravindranath switch (masked_ioasc) { 260689a36810SAnil Ravindranath 260789a36810SAnil Ravindranath case PMCRAID_IOASC_AC_TERMINATED_BY_HOST: 260889a36810SAnil Ravindranath scsi_cmd->result |= (DID_ABORT << 16); 260989a36810SAnil Ravindranath break; 261089a36810SAnil Ravindranath 261189a36810SAnil Ravindranath case PMCRAID_IOASC_IR_INVALID_RESOURCE_HANDLE: 261289a36810SAnil Ravindranath case PMCRAID_IOASC_HW_CANNOT_COMMUNICATE: 261389a36810SAnil Ravindranath scsi_cmd->result |= (DID_NO_CONNECT << 16); 261489a36810SAnil Ravindranath break; 261589a36810SAnil Ravindranath 261689a36810SAnil Ravindranath case PMCRAID_IOASC_NR_SYNC_REQUIRED: 261789a36810SAnil Ravindranath res->sync_reqd = 1; 261889a36810SAnil Ravindranath scsi_cmd->result |= (DID_IMM_RETRY << 16); 261989a36810SAnil Ravindranath break; 262089a36810SAnil Ravindranath 262189a36810SAnil Ravindranath case PMCRAID_IOASC_ME_READ_ERROR_NO_REALLOC: 262289a36810SAnil Ravindranath scsi_cmd->result |= (DID_PASSTHROUGH << 16); 262389a36810SAnil Ravindranath break; 262489a36810SAnil Ravindranath 262589a36810SAnil Ravindranath case PMCRAID_IOASC_UA_BUS_WAS_RESET: 262689a36810SAnil Ravindranath case PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER: 262789a36810SAnil Ravindranath if (!res->reset_progress) 262889a36810SAnil Ravindranath scsi_report_bus_reset(pinstance->host, 262989a36810SAnil Ravindranath scsi_cmd->device->channel); 263089a36810SAnil Ravindranath scsi_cmd->result |= (DID_ERROR << 16); 263189a36810SAnil Ravindranath break; 263289a36810SAnil Ravindranath 263389a36810SAnil Ravindranath case PMCRAID_IOASC_HW_DEVICE_BUS_STATUS_ERROR: 263489a36810SAnil Ravindranath scsi_cmd->result |= PMCRAID_IOASC_SENSE_STATUS(ioasc); 263589a36810SAnil Ravindranath res->sync_reqd = 1; 263689a36810SAnil Ravindranath 263789a36810SAnil Ravindranath /* if check_condition is not active return with error otherwise 263889a36810SAnil Ravindranath * get/frame the sense buffer 263989a36810SAnil Ravindranath */ 264089a36810SAnil Ravindranath if (PMCRAID_IOASC_SENSE_STATUS(ioasc) != 264189a36810SAnil Ravindranath SAM_STAT_CHECK_CONDITION && 264289a36810SAnil Ravindranath PMCRAID_IOASC_SENSE_STATUS(ioasc) != SAM_STAT_ACA_ACTIVE) 264389a36810SAnil Ravindranath return 0; 264489a36810SAnil Ravindranath 264589a36810SAnil Ravindranath /* If we have auto sense data as part of IOASA pass it to 264689a36810SAnil Ravindranath * mid-layer 264789a36810SAnil Ravindranath */ 264889a36810SAnil Ravindranath if (ioasa->auto_sense_length != 0) { 264945c80be6SArnd Bergmann short sense_len = le16_to_cpu(ioasa->auto_sense_length); 265045c80be6SArnd Bergmann int data_size = min_t(u16, sense_len, 265189a36810SAnil Ravindranath SCSI_SENSE_BUFFERSIZE); 265289a36810SAnil Ravindranath 265389a36810SAnil Ravindranath memcpy(scsi_cmd->sense_buffer, 265489a36810SAnil Ravindranath ioasa->sense_data, 265589a36810SAnil Ravindranath data_size); 2656203654b4SChristoph Hellwig sense_copied = true; 265789a36810SAnil Ravindranath } 265889a36810SAnil Ravindranath 2659a70757baSAnil Ravindranath if (RES_IS_GSCSI(res->cfg_entry)) 266089a36810SAnil Ravindranath pmcraid_cancel_all(cmd, sense_copied); 2661a70757baSAnil Ravindranath else if (sense_copied) 266289a36810SAnil Ravindranath pmcraid_erp_done(cmd); 2663a70757baSAnil Ravindranath else 266489a36810SAnil Ravindranath pmcraid_request_sense(cmd); 266589a36810SAnil Ravindranath 266689a36810SAnil Ravindranath return 1; 266789a36810SAnil Ravindranath 266889a36810SAnil Ravindranath case PMCRAID_IOASC_NR_INIT_CMD_REQUIRED: 266989a36810SAnil Ravindranath break; 267089a36810SAnil Ravindranath 267189a36810SAnil Ravindranath default: 267289a36810SAnil Ravindranath if (PMCRAID_IOASC_SENSE_KEY(ioasc) > RECOVERED_ERROR) 267389a36810SAnil Ravindranath scsi_cmd->result |= (DID_ERROR << 16); 267489a36810SAnil Ravindranath break; 267589a36810SAnil Ravindranath } 267689a36810SAnil Ravindranath return 0; 267789a36810SAnil Ravindranath } 267889a36810SAnil Ravindranath 267989a36810SAnil Ravindranath /** 268089a36810SAnil Ravindranath * pmcraid_reset_device - device reset handler functions 268189a36810SAnil Ravindranath * 268289a36810SAnil Ravindranath * @scsi_cmd: scsi command struct 26833673b7b0SLee Jones * @timeout: command timeout 268489a36810SAnil Ravindranath * @modifier: reset modifier indicating the reset sequence to be performed 268589a36810SAnil Ravindranath * 268689a36810SAnil Ravindranath * This function issues a device reset to the affected device. 268789a36810SAnil Ravindranath * A LUN reset will be sent to the device first. If that does 268889a36810SAnil Ravindranath * not work, a target reset will be sent. 268989a36810SAnil Ravindranath * 269089a36810SAnil Ravindranath * Return value: 269189a36810SAnil Ravindranath * SUCCESS / FAILED 269289a36810SAnil Ravindranath */ 269389a36810SAnil Ravindranath static int pmcraid_reset_device( 269489a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd, 269589a36810SAnil Ravindranath unsigned long timeout, 26963673b7b0SLee Jones u8 modifier) 269789a36810SAnil Ravindranath { 269889a36810SAnil Ravindranath struct pmcraid_cmd *cmd; 269989a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 270089a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 270189a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb; 270289a36810SAnil Ravindranath unsigned long lock_flags; 270389a36810SAnil Ravindranath u32 ioasc; 270489a36810SAnil Ravindranath 270589a36810SAnil Ravindranath pinstance = 270689a36810SAnil Ravindranath (struct pmcraid_instance *)scsi_cmd->device->host->hostdata; 270789a36810SAnil Ravindranath res = scsi_cmd->device->hostdata; 270889a36810SAnil Ravindranath 270989a36810SAnil Ravindranath if (!res) { 271034876402SAnil Ravindranath sdev_printk(KERN_ERR, scsi_cmd->device, 271134876402SAnil Ravindranath "reset_device: NULL resource pointer\n"); 271289a36810SAnil Ravindranath return FAILED; 271389a36810SAnil Ravindranath } 271489a36810SAnil Ravindranath 271589a36810SAnil Ravindranath /* If adapter is currently going through reset/reload, return failed. 271689a36810SAnil Ravindranath * This will force the mid-layer to call _eh_bus/host reset, which 271789a36810SAnil Ravindranath * will then go to sleep and wait for the reset to complete 271889a36810SAnil Ravindranath */ 271989a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 272089a36810SAnil Ravindranath if (pinstance->ioa_reset_in_progress || 272189a36810SAnil Ravindranath pinstance->ioa_state == IOA_STATE_DEAD) { 272289a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 272389a36810SAnil Ravindranath return FAILED; 272489a36810SAnil Ravindranath } 272589a36810SAnil Ravindranath 272689a36810SAnil Ravindranath res->reset_progress = 1; 272789a36810SAnil Ravindranath pmcraid_info("Resetting %s resource with addr %x\n", 272889a36810SAnil Ravindranath ((modifier & RESET_DEVICE_LUN) ? "LUN" : 272989a36810SAnil Ravindranath ((modifier & RESET_DEVICE_TARGET) ? "TARGET" : "BUS")), 273089a36810SAnil Ravindranath le32_to_cpu(res->cfg_entry.resource_address)); 273189a36810SAnil Ravindranath 273289a36810SAnil Ravindranath /* get a free cmd block */ 273389a36810SAnil Ravindranath cmd = pmcraid_get_free_cmd(pinstance); 273489a36810SAnil Ravindranath 273589a36810SAnil Ravindranath if (cmd == NULL) { 273689a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 273789a36810SAnil Ravindranath pmcraid_err("%s: no cmd blocks are available\n", __func__); 273889a36810SAnil Ravindranath return FAILED; 273989a36810SAnil Ravindranath } 274089a36810SAnil Ravindranath 274189a36810SAnil Ravindranath ioarcb = &cmd->ioa_cb->ioarcb; 274289a36810SAnil Ravindranath ioarcb->resource_handle = res->cfg_entry.resource_handle; 274389a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_IOACMD; 274489a36810SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_RESET_DEVICE; 274589a36810SAnil Ravindranath 274689a36810SAnil Ravindranath /* Initialize reset modifier bits */ 274789a36810SAnil Ravindranath if (modifier) 274889a36810SAnil Ravindranath modifier = ENABLE_RESET_MODIFIER | modifier; 274989a36810SAnil Ravindranath 275089a36810SAnil Ravindranath ioarcb->cdb[1] = modifier; 275189a36810SAnil Ravindranath 275289a36810SAnil Ravindranath init_completion(&cmd->wait_for_completion); 275389a36810SAnil Ravindranath cmd->completion_req = 1; 275489a36810SAnil Ravindranath 275589a36810SAnil Ravindranath pmcraid_info("cmd(CDB[0] = %x) for %x with index = %d\n", 275689a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 275789a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioarcb.resource_handle), 275889a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle) >> 2); 275989a36810SAnil Ravindranath 276089a36810SAnil Ravindranath pmcraid_send_cmd(cmd, 276189a36810SAnil Ravindranath pmcraid_internal_done, 276289a36810SAnil Ravindranath timeout, 276389a36810SAnil Ravindranath pmcraid_timeout_handler); 276489a36810SAnil Ravindranath 276589a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 276689a36810SAnil Ravindranath 276789a36810SAnil Ravindranath /* RESET_DEVICE command completes after all pending IOARCBs are 276889a36810SAnil Ravindranath * completed. Once this command is completed, pmcraind_internal_done 276989a36810SAnil Ravindranath * will wake up the 'completion' queue. 277089a36810SAnil Ravindranath */ 277189a36810SAnil Ravindranath wait_for_completion(&cmd->wait_for_completion); 277289a36810SAnil Ravindranath 277389a36810SAnil Ravindranath /* complete the command here itself and return the command block 277489a36810SAnil Ravindranath * to free list 277589a36810SAnil Ravindranath */ 277689a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 277789a36810SAnil Ravindranath res->reset_progress = 0; 277889a36810SAnil Ravindranath ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); 277989a36810SAnil Ravindranath 278089a36810SAnil Ravindranath /* set the return value based on the returned ioasc */ 278189a36810SAnil Ravindranath return PMCRAID_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS; 278289a36810SAnil Ravindranath } 278389a36810SAnil Ravindranath 278489a36810SAnil Ravindranath /** 278589a36810SAnil Ravindranath * _pmcraid_io_done - helper for pmcraid_io_done function 278689a36810SAnil Ravindranath * 278789a36810SAnil Ravindranath * @cmd: pointer to pmcraid command struct 278889a36810SAnil Ravindranath * @reslen: residual data length to be set in the ioasa 278989a36810SAnil Ravindranath * @ioasc: ioasc either returned by IOA or set by driver itself. 279089a36810SAnil Ravindranath * 279189a36810SAnil Ravindranath * This function is invoked by pmcraid_io_done to complete mid-layer 279289a36810SAnil Ravindranath * scsi ops. 279389a36810SAnil Ravindranath * 279489a36810SAnil Ravindranath * Return value: 279589a36810SAnil Ravindranath * 0 if caller is required to return it to free_pool. Returns 1 if 279689a36810SAnil Ravindranath * caller need not worry about freeing command block as error handler 279789a36810SAnil Ravindranath * will take care of that. 279889a36810SAnil Ravindranath */ 279989a36810SAnil Ravindranath 280089a36810SAnil Ravindranath static int _pmcraid_io_done(struct pmcraid_cmd *cmd, int reslen, int ioasc) 280189a36810SAnil Ravindranath { 280289a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; 280389a36810SAnil Ravindranath int rc = 0; 280489a36810SAnil Ravindranath 280589a36810SAnil Ravindranath scsi_set_resid(scsi_cmd, reslen); 280689a36810SAnil Ravindranath 280789a36810SAnil Ravindranath pmcraid_info("response(%d) CDB[0] = %x ioasc:result: %x:%x\n", 280889a36810SAnil Ravindranath le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle) >> 2, 280989a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 281089a36810SAnil Ravindranath ioasc, scsi_cmd->result); 281189a36810SAnil Ravindranath 281289a36810SAnil Ravindranath if (PMCRAID_IOASC_SENSE_KEY(ioasc) != 0) 281389a36810SAnil Ravindranath rc = pmcraid_error_handler(cmd); 281489a36810SAnil Ravindranath 281589a36810SAnil Ravindranath if (rc == 0) { 281689a36810SAnil Ravindranath scsi_dma_unmap(scsi_cmd); 2817f13cc234SBart Van Assche scsi_done(scsi_cmd); 281889a36810SAnil Ravindranath } 281989a36810SAnil Ravindranath 282089a36810SAnil Ravindranath return rc; 282189a36810SAnil Ravindranath } 282289a36810SAnil Ravindranath 282389a36810SAnil Ravindranath /** 282489a36810SAnil Ravindranath * pmcraid_io_done - SCSI completion function 282589a36810SAnil Ravindranath * 282689a36810SAnil Ravindranath * @cmd: pointer to pmcraid command struct 282789a36810SAnil Ravindranath * 282889a36810SAnil Ravindranath * This function is invoked by tasklet/mid-layer error handler to completing 282989a36810SAnil Ravindranath * the SCSI ops sent from mid-layer. 283089a36810SAnil Ravindranath * 283189a36810SAnil Ravindranath * Return value 283289a36810SAnil Ravindranath * none 283389a36810SAnil Ravindranath */ 283489a36810SAnil Ravindranath 283589a36810SAnil Ravindranath static void pmcraid_io_done(struct pmcraid_cmd *cmd) 283689a36810SAnil Ravindranath { 283789a36810SAnil Ravindranath u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); 283889a36810SAnil Ravindranath u32 reslen = le32_to_cpu(cmd->ioa_cb->ioasa.residual_data_length); 283989a36810SAnil Ravindranath 284089a36810SAnil Ravindranath if (_pmcraid_io_done(cmd, reslen, ioasc) == 0) 284189a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 284289a36810SAnil Ravindranath } 284389a36810SAnil Ravindranath 284489a36810SAnil Ravindranath /** 284589a36810SAnil Ravindranath * pmcraid_abort_cmd - Aborts a single IOARCB already submitted to IOA 284689a36810SAnil Ravindranath * 284789a36810SAnil Ravindranath * @cmd: command block of the command to be aborted 284889a36810SAnil Ravindranath * 284989a36810SAnil Ravindranath * Return Value: 285089a36810SAnil Ravindranath * returns pointer to command structure used as cancelling cmd 285189a36810SAnil Ravindranath */ 285289a36810SAnil Ravindranath static struct pmcraid_cmd *pmcraid_abort_cmd(struct pmcraid_cmd *cmd) 285389a36810SAnil Ravindranath { 285489a36810SAnil Ravindranath struct pmcraid_cmd *cancel_cmd; 285589a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 285689a36810SAnil Ravindranath 285789a36810SAnil Ravindranath pinstance = (struct pmcraid_instance *)cmd->drv_inst; 285889a36810SAnil Ravindranath 285989a36810SAnil Ravindranath cancel_cmd = pmcraid_get_free_cmd(pinstance); 286089a36810SAnil Ravindranath 286189a36810SAnil Ravindranath if (cancel_cmd == NULL) { 286289a36810SAnil Ravindranath pmcraid_err("%s: no cmd blocks are available\n", __func__); 286389a36810SAnil Ravindranath return NULL; 286489a36810SAnil Ravindranath } 286589a36810SAnil Ravindranath 286689a36810SAnil Ravindranath pmcraid_prepare_cancel_cmd(cancel_cmd, cmd); 286789a36810SAnil Ravindranath 286889a36810SAnil Ravindranath pmcraid_info("aborting command CDB[0]= %x with index = %d\n", 286989a36810SAnil Ravindranath cmd->ioa_cb->ioarcb.cdb[0], 287045c80be6SArnd Bergmann le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle) >> 2); 287189a36810SAnil Ravindranath 287289a36810SAnil Ravindranath init_completion(&cancel_cmd->wait_for_completion); 287389a36810SAnil Ravindranath cancel_cmd->completion_req = 1; 287489a36810SAnil Ravindranath 287589a36810SAnil Ravindranath pmcraid_info("command (%d) CDB[0] = %x for %x\n", 287689a36810SAnil Ravindranath le32_to_cpu(cancel_cmd->ioa_cb->ioarcb.response_handle) >> 2, 2877c20c4267SAnil Ravindranath cancel_cmd->ioa_cb->ioarcb.cdb[0], 287889a36810SAnil Ravindranath le32_to_cpu(cancel_cmd->ioa_cb->ioarcb.resource_handle)); 287989a36810SAnil Ravindranath 288089a36810SAnil Ravindranath pmcraid_send_cmd(cancel_cmd, 288189a36810SAnil Ravindranath pmcraid_internal_done, 288289a36810SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, 288389a36810SAnil Ravindranath pmcraid_timeout_handler); 288489a36810SAnil Ravindranath return cancel_cmd; 288589a36810SAnil Ravindranath } 288689a36810SAnil Ravindranath 288789a36810SAnil Ravindranath /** 288889a36810SAnil Ravindranath * pmcraid_abort_complete - Waits for ABORT TASK completion 288989a36810SAnil Ravindranath * 289089a36810SAnil Ravindranath * @cancel_cmd: command block use as cancelling command 289189a36810SAnil Ravindranath * 289289a36810SAnil Ravindranath * Return Value: 289389a36810SAnil Ravindranath * returns SUCCESS if ABORT TASK has good completion 289489a36810SAnil Ravindranath * otherwise FAILED 289589a36810SAnil Ravindranath */ 289689a36810SAnil Ravindranath static int pmcraid_abort_complete(struct pmcraid_cmd *cancel_cmd) 289789a36810SAnil Ravindranath { 289889a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 289989a36810SAnil Ravindranath u32 ioasc; 290089a36810SAnil Ravindranath 290189a36810SAnil Ravindranath wait_for_completion(&cancel_cmd->wait_for_completion); 2902c20c4267SAnil Ravindranath res = cancel_cmd->res; 2903c20c4267SAnil Ravindranath cancel_cmd->res = NULL; 290489a36810SAnil Ravindranath ioasc = le32_to_cpu(cancel_cmd->ioa_cb->ioasa.ioasc); 290589a36810SAnil Ravindranath 290689a36810SAnil Ravindranath /* If the abort task is not timed out we will get a Good completion 290789a36810SAnil Ravindranath * as sense_key, otherwise we may get one the following responses 290825985edcSLucas De Marchi * due to subsequent bus reset or device reset. In case IOASC is 290989a36810SAnil Ravindranath * NR_SYNC_REQUIRED, set sync_reqd flag for the corresponding resource 291089a36810SAnil Ravindranath */ 291189a36810SAnil Ravindranath if (ioasc == PMCRAID_IOASC_UA_BUS_WAS_RESET || 291289a36810SAnil Ravindranath ioasc == PMCRAID_IOASC_NR_SYNC_REQUIRED) { 291389a36810SAnil Ravindranath if (ioasc == PMCRAID_IOASC_NR_SYNC_REQUIRED) 291489a36810SAnil Ravindranath res->sync_reqd = 1; 291589a36810SAnil Ravindranath ioasc = 0; 291689a36810SAnil Ravindranath } 291789a36810SAnil Ravindranath 291889a36810SAnil Ravindranath /* complete the command here itself */ 291989a36810SAnil Ravindranath pmcraid_return_cmd(cancel_cmd); 292089a36810SAnil Ravindranath return PMCRAID_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS; 292189a36810SAnil Ravindranath } 292289a36810SAnil Ravindranath 292389a36810SAnil Ravindranath /** 292489a36810SAnil Ravindranath * pmcraid_eh_abort_handler - entry point for aborting a single task on errors 292589a36810SAnil Ravindranath * 292689a36810SAnil Ravindranath * @scsi_cmd: scsi command struct given by mid-layer. When this is called 292789a36810SAnil Ravindranath * mid-layer ensures that no other commands are queued. This 292889a36810SAnil Ravindranath * never gets called under interrupt, but a separate eh thread. 292989a36810SAnil Ravindranath * 293089a36810SAnil Ravindranath * Return value: 293189a36810SAnil Ravindranath * SUCCESS / FAILED 293289a36810SAnil Ravindranath */ 293389a36810SAnil Ravindranath static int pmcraid_eh_abort_handler(struct scsi_cmnd *scsi_cmd) 293489a36810SAnil Ravindranath { 293589a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 293689a36810SAnil Ravindranath struct pmcraid_cmd *cmd; 293789a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 293889a36810SAnil Ravindranath unsigned long host_lock_flags; 293989a36810SAnil Ravindranath unsigned long pending_lock_flags; 294089a36810SAnil Ravindranath struct pmcraid_cmd *cancel_cmd = NULL; 294189a36810SAnil Ravindranath int cmd_found = 0; 294289a36810SAnil Ravindranath int rc = FAILED; 294389a36810SAnil Ravindranath 294489a36810SAnil Ravindranath pinstance = 294589a36810SAnil Ravindranath (struct pmcraid_instance *)scsi_cmd->device->host->hostdata; 294689a36810SAnil Ravindranath 294734876402SAnil Ravindranath scmd_printk(KERN_INFO, scsi_cmd, 294889a36810SAnil Ravindranath "I/O command timed out, aborting it.\n"); 294989a36810SAnil Ravindranath 295089a36810SAnil Ravindranath res = scsi_cmd->device->hostdata; 295189a36810SAnil Ravindranath 295289a36810SAnil Ravindranath if (res == NULL) 295389a36810SAnil Ravindranath return rc; 295489a36810SAnil Ravindranath 295589a36810SAnil Ravindranath /* If we are currently going through reset/reload, return failed. 295689a36810SAnil Ravindranath * This will force the mid-layer to eventually call 295789a36810SAnil Ravindranath * pmcraid_eh_host_reset which will then go to sleep and wait for the 295889a36810SAnil Ravindranath * reset to complete 295989a36810SAnil Ravindranath */ 296089a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, host_lock_flags); 296189a36810SAnil Ravindranath 296289a36810SAnil Ravindranath if (pinstance->ioa_reset_in_progress || 296389a36810SAnil Ravindranath pinstance->ioa_state == IOA_STATE_DEAD) { 296489a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 296589a36810SAnil Ravindranath host_lock_flags); 296689a36810SAnil Ravindranath return rc; 296789a36810SAnil Ravindranath } 296889a36810SAnil Ravindranath 296989a36810SAnil Ravindranath /* loop over pending cmd list to find cmd corresponding to this 297089a36810SAnil Ravindranath * scsi_cmd. Note that this command might not have been completed 297189a36810SAnil Ravindranath * already. locking: all pending commands are protected with 297289a36810SAnil Ravindranath * pending_pool_lock. 297389a36810SAnil Ravindranath */ 297489a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->pending_pool_lock, pending_lock_flags); 297589a36810SAnil Ravindranath list_for_each_entry(cmd, &pinstance->pending_cmd_pool, free_list) { 297689a36810SAnil Ravindranath 297789a36810SAnil Ravindranath if (cmd->scsi_cmd == scsi_cmd) { 297889a36810SAnil Ravindranath cmd_found = 1; 297989a36810SAnil Ravindranath break; 298089a36810SAnil Ravindranath } 298189a36810SAnil Ravindranath } 298289a36810SAnil Ravindranath 298389a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->pending_pool_lock, 298489a36810SAnil Ravindranath pending_lock_flags); 298589a36810SAnil Ravindranath 298689a36810SAnil Ravindranath /* If the command to be aborted was given to IOA and still pending with 298789a36810SAnil Ravindranath * it, send ABORT_TASK to abort this and wait for its completion 298889a36810SAnil Ravindranath */ 298989a36810SAnil Ravindranath if (cmd_found) 299089a36810SAnil Ravindranath cancel_cmd = pmcraid_abort_cmd(cmd); 299189a36810SAnil Ravindranath 299289a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 299389a36810SAnil Ravindranath host_lock_flags); 299489a36810SAnil Ravindranath 299589a36810SAnil Ravindranath if (cancel_cmd) { 2996c20c4267SAnil Ravindranath cancel_cmd->res = cmd->scsi_cmd->device->hostdata; 299789a36810SAnil Ravindranath rc = pmcraid_abort_complete(cancel_cmd); 299889a36810SAnil Ravindranath } 299989a36810SAnil Ravindranath 300089a36810SAnil Ravindranath return cmd_found ? rc : SUCCESS; 300189a36810SAnil Ravindranath } 300289a36810SAnil Ravindranath 300389a36810SAnil Ravindranath /** 30043673b7b0SLee Jones * pmcraid_eh_device_reset_handler - bus/target/device reset handler callbacks 300589a36810SAnil Ravindranath * 300689a36810SAnil Ravindranath * @scmd: pointer to scsi_cmd that was sent to the resource to be reset. 300789a36810SAnil Ravindranath * 300889a36810SAnil Ravindranath * All these routines invokve pmcraid_reset_device with appropriate parameters. 300989a36810SAnil Ravindranath * Since these are called from mid-layer EH thread, no other IO will be queued 301089a36810SAnil Ravindranath * to the resource being reset. However, control path (IOCTL) may be active so 301189a36810SAnil Ravindranath * it is necessary to synchronize IOARRIN writes which pmcraid_reset_device 301289a36810SAnil Ravindranath * takes care by locking/unlocking host_lock. 301389a36810SAnil Ravindranath * 301489a36810SAnil Ravindranath * Return value 301589a36810SAnil Ravindranath * SUCCESS or FAILED 301689a36810SAnil Ravindranath */ 301789a36810SAnil Ravindranath static int pmcraid_eh_device_reset_handler(struct scsi_cmnd *scmd) 301889a36810SAnil Ravindranath { 301934876402SAnil Ravindranath scmd_printk(KERN_INFO, scmd, 302034876402SAnil Ravindranath "resetting device due to an I/O command timeout.\n"); 302189a36810SAnil Ravindranath return pmcraid_reset_device(scmd, 302289a36810SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, 302389a36810SAnil Ravindranath RESET_DEVICE_LUN); 302489a36810SAnil Ravindranath } 302589a36810SAnil Ravindranath 302689a36810SAnil Ravindranath static int pmcraid_eh_bus_reset_handler(struct scsi_cmnd *scmd) 302789a36810SAnil Ravindranath { 302834876402SAnil Ravindranath scmd_printk(KERN_INFO, scmd, 302934876402SAnil Ravindranath "Doing bus reset due to an I/O command timeout.\n"); 303089a36810SAnil Ravindranath return pmcraid_reset_device(scmd, 303189a36810SAnil Ravindranath PMCRAID_RESET_BUS_TIMEOUT, 303289a36810SAnil Ravindranath RESET_DEVICE_BUS); 303389a36810SAnil Ravindranath } 303489a36810SAnil Ravindranath 303589a36810SAnil Ravindranath static int pmcraid_eh_target_reset_handler(struct scsi_cmnd *scmd) 303689a36810SAnil Ravindranath { 303734876402SAnil Ravindranath scmd_printk(KERN_INFO, scmd, 303834876402SAnil Ravindranath "Doing target reset due to an I/O command timeout.\n"); 303989a36810SAnil Ravindranath return pmcraid_reset_device(scmd, 304089a36810SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, 304189a36810SAnil Ravindranath RESET_DEVICE_TARGET); 304289a36810SAnil Ravindranath } 304389a36810SAnil Ravindranath 304489a36810SAnil Ravindranath /** 304589a36810SAnil Ravindranath * pmcraid_eh_host_reset_handler - adapter reset handler callback 304689a36810SAnil Ravindranath * 304789a36810SAnil Ravindranath * @scmd: pointer to scsi_cmd that was sent to a resource of adapter 304889a36810SAnil Ravindranath * 304989a36810SAnil Ravindranath * Initiates adapter reset to bring it up to operational state 305089a36810SAnil Ravindranath * 305189a36810SAnil Ravindranath * Return value 305289a36810SAnil Ravindranath * SUCCESS or FAILED 305389a36810SAnil Ravindranath */ 305489a36810SAnil Ravindranath static int pmcraid_eh_host_reset_handler(struct scsi_cmnd *scmd) 305589a36810SAnil Ravindranath { 305689a36810SAnil Ravindranath unsigned long interval = 10000; /* 10 seconds interval */ 305789a36810SAnil Ravindranath int waits = jiffies_to_msecs(PMCRAID_RESET_HOST_TIMEOUT) / interval; 305889a36810SAnil Ravindranath struct pmcraid_instance *pinstance = 305989a36810SAnil Ravindranath (struct pmcraid_instance *)(scmd->device->host->hostdata); 306089a36810SAnil Ravindranath 306189a36810SAnil Ravindranath 306289a36810SAnil Ravindranath /* wait for an additional 150 seconds just in case firmware could come 306389a36810SAnil Ravindranath * up and if it could complete all the pending commands excluding the 306489a36810SAnil Ravindranath * two HCAM (CCN and LDN). 306589a36810SAnil Ravindranath */ 306689a36810SAnil Ravindranath while (waits--) { 306789a36810SAnil Ravindranath if (atomic_read(&pinstance->outstanding_cmds) <= 306889a36810SAnil Ravindranath PMCRAID_MAX_HCAM_CMD) 306989a36810SAnil Ravindranath return SUCCESS; 307089a36810SAnil Ravindranath msleep(interval); 307189a36810SAnil Ravindranath } 307289a36810SAnil Ravindranath 307389a36810SAnil Ravindranath dev_err(&pinstance->pdev->dev, 307489a36810SAnil Ravindranath "Adapter being reset due to an I/O command timeout.\n"); 307589a36810SAnil Ravindranath return pmcraid_reset_bringup(pinstance) == 0 ? SUCCESS : FAILED; 307689a36810SAnil Ravindranath } 307789a36810SAnil Ravindranath 307889a36810SAnil Ravindranath /** 307989a36810SAnil Ravindranath * pmcraid_init_ioadls - initializes IOADL related fields in IOARCB 308089a36810SAnil Ravindranath * @cmd: pmcraid command struct 308189a36810SAnil Ravindranath * @sgcount: count of scatter-gather elements 308289a36810SAnil Ravindranath * 308389a36810SAnil Ravindranath * Return value 308489a36810SAnil Ravindranath * returns pointer pmcraid_ioadl_desc, initialized to point to internal 308589a36810SAnil Ravindranath * or external IOADLs 308689a36810SAnil Ravindranath */ 308761b96d5bSBaoyou Xie static struct pmcraid_ioadl_desc * 308889a36810SAnil Ravindranath pmcraid_init_ioadls(struct pmcraid_cmd *cmd, int sgcount) 308989a36810SAnil Ravindranath { 309089a36810SAnil Ravindranath struct pmcraid_ioadl_desc *ioadl; 309189a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 309289a36810SAnil Ravindranath int ioadl_count = 0; 309389a36810SAnil Ravindranath 309489a36810SAnil Ravindranath if (ioarcb->add_cmd_param_length) 309545c80be6SArnd Bergmann ioadl_count = DIV_ROUND_UP(le16_to_cpu(ioarcb->add_cmd_param_length), 16); 309645c80be6SArnd Bergmann ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc) * sgcount); 309789a36810SAnil Ravindranath 309889a36810SAnil Ravindranath if ((sgcount + ioadl_count) > (ARRAY_SIZE(ioarcb->add_data.u.ioadl))) { 309989a36810SAnil Ravindranath /* external ioadls start at offset 0x80 from control_block 310089a36810SAnil Ravindranath * structure, re-using 24 out of 27 ioadls part of IOARCB. 310189a36810SAnil Ravindranath * It is necessary to indicate to firmware that driver is 310289a36810SAnil Ravindranath * using ioadls to be treated as external to IOARCB. 310389a36810SAnil Ravindranath */ 310445c80be6SArnd Bergmann ioarcb->ioarcb_bus_addr &= cpu_to_le64(~(0x1FULL)); 310589a36810SAnil Ravindranath ioarcb->ioadl_bus_addr = 310689a36810SAnil Ravindranath cpu_to_le64((cmd->ioa_cb_bus_addr) + 310789a36810SAnil Ravindranath offsetof(struct pmcraid_ioarcb, 310889a36810SAnil Ravindranath add_data.u.ioadl[3])); 310989a36810SAnil Ravindranath ioadl = &ioarcb->add_data.u.ioadl[3]; 311089a36810SAnil Ravindranath } else { 311189a36810SAnil Ravindranath ioarcb->ioadl_bus_addr = 311289a36810SAnil Ravindranath cpu_to_le64((cmd->ioa_cb_bus_addr) + 311389a36810SAnil Ravindranath offsetof(struct pmcraid_ioarcb, 311489a36810SAnil Ravindranath add_data.u.ioadl[ioadl_count])); 311589a36810SAnil Ravindranath 311689a36810SAnil Ravindranath ioadl = &ioarcb->add_data.u.ioadl[ioadl_count]; 311789a36810SAnil Ravindranath ioarcb->ioarcb_bus_addr |= 311845c80be6SArnd Bergmann cpu_to_le64(DIV_ROUND_CLOSEST(sgcount + ioadl_count, 8)); 311989a36810SAnil Ravindranath } 312089a36810SAnil Ravindranath 312189a36810SAnil Ravindranath return ioadl; 312289a36810SAnil Ravindranath } 312389a36810SAnil Ravindranath 312489a36810SAnil Ravindranath /** 312589a36810SAnil Ravindranath * pmcraid_build_ioadl - Build a scatter/gather list and map the buffer 312689a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 312789a36810SAnil Ravindranath * @cmd: pmcraid command struct 312889a36810SAnil Ravindranath * 312989a36810SAnil Ravindranath * This function is invoked by queuecommand entry point while sending a command 313089a36810SAnil Ravindranath * to firmware. This builds ioadl descriptors and sets up ioarcb fields. 313189a36810SAnil Ravindranath * 313289a36810SAnil Ravindranath * Return value: 313389a36810SAnil Ravindranath * 0 on success or -1 on failure 313489a36810SAnil Ravindranath */ 313589a36810SAnil Ravindranath static int pmcraid_build_ioadl( 313689a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 313789a36810SAnil Ravindranath struct pmcraid_cmd *cmd 313889a36810SAnil Ravindranath ) 313989a36810SAnil Ravindranath { 314089a36810SAnil Ravindranath int i, nseg; 314189a36810SAnil Ravindranath struct scatterlist *sglist; 314289a36810SAnil Ravindranath 314389a36810SAnil Ravindranath struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; 314489a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &(cmd->ioa_cb->ioarcb); 3145b22ee87dSColin Ian King struct pmcraid_ioadl_desc *ioadl; 314689a36810SAnil Ravindranath 314789a36810SAnil Ravindranath u32 length = scsi_bufflen(scsi_cmd); 314889a36810SAnil Ravindranath 314989a36810SAnil Ravindranath if (!length) 315089a36810SAnil Ravindranath return 0; 315189a36810SAnil Ravindranath 315289a36810SAnil Ravindranath nseg = scsi_dma_map(scsi_cmd); 315389a36810SAnil Ravindranath 315489a36810SAnil Ravindranath if (nseg < 0) { 315534876402SAnil Ravindranath scmd_printk(KERN_ERR, scsi_cmd, "scsi_map_dma failed!\n"); 315689a36810SAnil Ravindranath return -1; 315789a36810SAnil Ravindranath } else if (nseg > PMCRAID_MAX_IOADLS) { 315889a36810SAnil Ravindranath scsi_dma_unmap(scsi_cmd); 315934876402SAnil Ravindranath scmd_printk(KERN_ERR, scsi_cmd, 316089a36810SAnil Ravindranath "sg count is (%d) more than allowed!\n", nseg); 316189a36810SAnil Ravindranath return -1; 316289a36810SAnil Ravindranath } 316389a36810SAnil Ravindranath 316489a36810SAnil Ravindranath /* Initialize IOARCB data transfer length fields */ 316589a36810SAnil Ravindranath if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) 316689a36810SAnil Ravindranath ioarcb->request_flags0 |= TRANSFER_DIR_WRITE; 316789a36810SAnil Ravindranath 316889a36810SAnil Ravindranath ioarcb->request_flags0 |= NO_LINK_DESCS; 316989a36810SAnil Ravindranath ioarcb->data_transfer_length = cpu_to_le32(length); 317089a36810SAnil Ravindranath ioadl = pmcraid_init_ioadls(cmd, nseg); 317189a36810SAnil Ravindranath 317289a36810SAnil Ravindranath /* Initialize IOADL descriptor addresses */ 317389a36810SAnil Ravindranath scsi_for_each_sg(scsi_cmd, sglist, nseg, i) { 317489a36810SAnil Ravindranath ioadl[i].data_len = cpu_to_le32(sg_dma_len(sglist)); 317589a36810SAnil Ravindranath ioadl[i].address = cpu_to_le64(sg_dma_address(sglist)); 317689a36810SAnil Ravindranath ioadl[i].flags = 0; 317789a36810SAnil Ravindranath } 317889a36810SAnil Ravindranath /* setup last descriptor */ 317988197966SAnil Ravindranath ioadl[i - 1].flags = IOADL_FLAGS_LAST_DESC; 318089a36810SAnil Ravindranath 318189a36810SAnil Ravindranath return 0; 318289a36810SAnil Ravindranath } 318389a36810SAnil Ravindranath 318489a36810SAnil Ravindranath /** 31853673b7b0SLee Jones * pmcraid_queuecommand_lck - Queue a mid-layer request 318689a36810SAnil Ravindranath * @scsi_cmd: scsi command struct 318789a36810SAnil Ravindranath * 318889a36810SAnil Ravindranath * This function queues a request generated by the mid-layer. Midlayer calls 318989a36810SAnil Ravindranath * this routine within host->lock. Some of the functions called by queuecommand 319089a36810SAnil Ravindranath * would use cmd block queue locks (free_pool_lock and pending_pool_lock) 319189a36810SAnil Ravindranath * 319289a36810SAnil Ravindranath * Return value: 319389a36810SAnil Ravindranath * 0 on success 319489a36810SAnil Ravindranath * SCSI_MLQUEUE_DEVICE_BUSY if device is busy 319589a36810SAnil Ravindranath * SCSI_MLQUEUE_HOST_BUSY if host is busy 319689a36810SAnil Ravindranath */ 3197af049dfdSBart Van Assche static int pmcraid_queuecommand_lck(struct scsi_cmnd *scsi_cmd) 319889a36810SAnil Ravindranath { 319989a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 320089a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 320189a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb; 320289a36810SAnil Ravindranath struct pmcraid_cmd *cmd; 3203c20c4267SAnil Ravindranath u32 fw_version; 320489a36810SAnil Ravindranath int rc = 0; 320589a36810SAnil Ravindranath 320689a36810SAnil Ravindranath pinstance = 320789a36810SAnil Ravindranath (struct pmcraid_instance *)scsi_cmd->device->host->hostdata; 3208c20c4267SAnil Ravindranath fw_version = be16_to_cpu(pinstance->inq_data->fw_version); 320989a36810SAnil Ravindranath res = scsi_cmd->device->hostdata; 321089a36810SAnil Ravindranath scsi_cmd->result = (DID_OK << 16); 321189a36810SAnil Ravindranath 321289a36810SAnil Ravindranath /* if adapter is marked as dead, set result to DID_NO_CONNECT complete 321389a36810SAnil Ravindranath * the command 321489a36810SAnil Ravindranath */ 321589a36810SAnil Ravindranath if (pinstance->ioa_state == IOA_STATE_DEAD) { 321689a36810SAnil Ravindranath pmcraid_info("IOA is dead, but queuecommand is scheduled\n"); 321789a36810SAnil Ravindranath scsi_cmd->result = (DID_NO_CONNECT << 16); 3218f13cc234SBart Van Assche scsi_done(scsi_cmd); 321989a36810SAnil Ravindranath return 0; 322089a36810SAnil Ravindranath } 322189a36810SAnil Ravindranath 322289a36810SAnil Ravindranath /* If IOA reset is in progress, can't queue the commands */ 322389a36810SAnil Ravindranath if (pinstance->ioa_reset_in_progress) 322489a36810SAnil Ravindranath return SCSI_MLQUEUE_HOST_BUSY; 322589a36810SAnil Ravindranath 3226c20c4267SAnil Ravindranath /* Firmware doesn't support SYNCHRONIZE_CACHE command (0x35), complete 3227c20c4267SAnil Ravindranath * the command here itself with success return 3228c20c4267SAnil Ravindranath */ 3229c20c4267SAnil Ravindranath if (scsi_cmd->cmnd[0] == SYNCHRONIZE_CACHE) { 3230c20c4267SAnil Ravindranath pmcraid_info("SYNC_CACHE(0x35), completing in driver itself\n"); 3231f13cc234SBart Van Assche scsi_done(scsi_cmd); 3232c20c4267SAnil Ravindranath return 0; 3233c20c4267SAnil Ravindranath } 3234c20c4267SAnil Ravindranath 323589a36810SAnil Ravindranath /* initialize the command and IOARCB to be sent to IOA */ 323689a36810SAnil Ravindranath cmd = pmcraid_get_free_cmd(pinstance); 323789a36810SAnil Ravindranath 323889a36810SAnil Ravindranath if (cmd == NULL) { 323989a36810SAnil Ravindranath pmcraid_err("free command block is not available\n"); 324089a36810SAnil Ravindranath return SCSI_MLQUEUE_HOST_BUSY; 324189a36810SAnil Ravindranath } 324289a36810SAnil Ravindranath 324389a36810SAnil Ravindranath cmd->scsi_cmd = scsi_cmd; 324489a36810SAnil Ravindranath ioarcb = &(cmd->ioa_cb->ioarcb); 324589a36810SAnil Ravindranath memcpy(ioarcb->cdb, scsi_cmd->cmnd, scsi_cmd->cmd_len); 324689a36810SAnil Ravindranath ioarcb->resource_handle = res->cfg_entry.resource_handle; 324789a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_SCSI; 324889a36810SAnil Ravindranath 3249c20c4267SAnil Ravindranath /* set hrrq number where the IOA should respond to. Note that all cmds 3250c20c4267SAnil Ravindranath * generated internally uses hrrq_id 0, exception to this is the cmd 3251c20c4267SAnil Ravindranath * block of scsi_cmd which is re-used (e.g. cancel/abort), which uses 3252c20c4267SAnil Ravindranath * hrrq_id assigned here in queuecommand 3253c20c4267SAnil Ravindranath */ 3254c20c4267SAnil Ravindranath ioarcb->hrrq_id = atomic_add_return(1, &(pinstance->last_message_id)) % 3255c20c4267SAnil Ravindranath pinstance->num_hrrq; 325689a36810SAnil Ravindranath cmd->cmd_done = pmcraid_io_done; 325789a36810SAnil Ravindranath 325889a36810SAnil Ravindranath if (RES_IS_GSCSI(res->cfg_entry) || RES_IS_VSET(res->cfg_entry)) { 325989a36810SAnil Ravindranath if (scsi_cmd->underflow == 0) 326089a36810SAnil Ravindranath ioarcb->request_flags0 |= INHIBIT_UL_CHECK; 326189a36810SAnil Ravindranath 326289a36810SAnil Ravindranath if (res->sync_reqd) { 326389a36810SAnil Ravindranath ioarcb->request_flags0 |= SYNC_COMPLETE; 326489a36810SAnil Ravindranath res->sync_reqd = 0; 326589a36810SAnil Ravindranath } 326689a36810SAnil Ravindranath 326789a36810SAnil Ravindranath ioarcb->request_flags0 |= NO_LINK_DESCS; 326850668633SChristoph Hellwig 326950668633SChristoph Hellwig if (scsi_cmd->flags & SCMD_TAGGED) 327050668633SChristoph Hellwig ioarcb->request_flags1 |= TASK_TAG_SIMPLE; 327189a36810SAnil Ravindranath 327289a36810SAnil Ravindranath if (RES_IS_GSCSI(res->cfg_entry)) 327389a36810SAnil Ravindranath ioarcb->request_flags1 |= DELAY_AFTER_RESET; 327489a36810SAnil Ravindranath } 327589a36810SAnil Ravindranath 327689a36810SAnil Ravindranath rc = pmcraid_build_ioadl(pinstance, cmd); 327789a36810SAnil Ravindranath 327889a36810SAnil Ravindranath pmcraid_info("command (%d) CDB[0] = %x for %x:%x:%x:%x\n", 327989a36810SAnil Ravindranath le32_to_cpu(ioarcb->response_handle) >> 2, 328089a36810SAnil Ravindranath scsi_cmd->cmnd[0], pinstance->host->unique_id, 328189a36810SAnil Ravindranath RES_IS_VSET(res->cfg_entry) ? PMCRAID_VSET_BUS_ID : 328289a36810SAnil Ravindranath PMCRAID_PHYS_BUS_ID, 328389a36810SAnil Ravindranath RES_IS_VSET(res->cfg_entry) ? 3284c20c4267SAnil Ravindranath (fw_version <= PMCRAID_FW_VERSION_1 ? 328589a36810SAnil Ravindranath res->cfg_entry.unique_flags1 : 328645c80be6SArnd Bergmann le16_to_cpu(res->cfg_entry.array_id) & 0xFF) : 328789a36810SAnil Ravindranath RES_TARGET(res->cfg_entry.resource_address), 328889a36810SAnil Ravindranath RES_LUN(res->cfg_entry.resource_address)); 328989a36810SAnil Ravindranath 329089a36810SAnil Ravindranath if (likely(rc == 0)) { 329189a36810SAnil Ravindranath _pmcraid_fire_command(cmd); 329289a36810SAnil Ravindranath } else { 329389a36810SAnil Ravindranath pmcraid_err("queuecommand could not build ioadl\n"); 329489a36810SAnil Ravindranath pmcraid_return_cmd(cmd); 329589a36810SAnil Ravindranath rc = SCSI_MLQUEUE_HOST_BUSY; 329689a36810SAnil Ravindranath } 329789a36810SAnil Ravindranath 329889a36810SAnil Ravindranath return rc; 329989a36810SAnil Ravindranath } 330089a36810SAnil Ravindranath 3301f281233dSJeff Garzik static DEF_SCSI_QCMD(pmcraid_queuecommand) 3302f281233dSJeff Garzik 33033673b7b0SLee Jones /* 330489a36810SAnil Ravindranath * pmcraid_open -char node "open" entry, allowed only users with admin access 330589a36810SAnil Ravindranath */ 330689a36810SAnil Ravindranath static int pmcraid_chr_open(struct inode *inode, struct file *filep) 330789a36810SAnil Ravindranath { 330889a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 330989a36810SAnil Ravindranath 331089a36810SAnil Ravindranath if (!capable(CAP_SYS_ADMIN)) 331189a36810SAnil Ravindranath return -EACCES; 331289a36810SAnil Ravindranath 331389a36810SAnil Ravindranath /* Populate adapter instance * pointer for use by ioctl */ 331489a36810SAnil Ravindranath pinstance = container_of(inode->i_cdev, struct pmcraid_instance, cdev); 331589a36810SAnil Ravindranath filep->private_data = pinstance; 331689a36810SAnil Ravindranath 331789a36810SAnil Ravindranath return 0; 331889a36810SAnil Ravindranath } 331989a36810SAnil Ravindranath 33203673b7b0SLee Jones /* 332189a36810SAnil Ravindranath * pmcraid_fasync - Async notifier registration from applications 332289a36810SAnil Ravindranath * 332389a36810SAnil Ravindranath * This function adds the calling process to a driver global queue. When an 332489a36810SAnil Ravindranath * event occurs, SIGIO will be sent to all processes in this queue. 332589a36810SAnil Ravindranath */ 332689a36810SAnil Ravindranath static int pmcraid_chr_fasync(int fd, struct file *filep, int mode) 332789a36810SAnil Ravindranath { 332889a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 332989a36810SAnil Ravindranath int rc; 333089a36810SAnil Ravindranath 3331660bdddbSCyril Jayaprakash pinstance = filep->private_data; 333289a36810SAnil Ravindranath mutex_lock(&pinstance->aen_queue_lock); 333389a36810SAnil Ravindranath rc = fasync_helper(fd, filep, mode, &pinstance->aen_queue); 333489a36810SAnil Ravindranath mutex_unlock(&pinstance->aen_queue_lock); 333589a36810SAnil Ravindranath 333689a36810SAnil Ravindranath return rc; 333789a36810SAnil Ravindranath } 333889a36810SAnil Ravindranath 333989a36810SAnil Ravindranath /** 334089a36810SAnil Ravindranath * pmcraid_ioctl_driver - ioctl handler for commands handled by driver itself 334189a36810SAnil Ravindranath * 334289a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 334389a36810SAnil Ravindranath * @cmd: ioctl command passed in 334489a36810SAnil Ravindranath * @buflen: length of user_buffer 334589a36810SAnil Ravindranath * @user_buffer: user buffer pointer 334689a36810SAnil Ravindranath * 334789a36810SAnil Ravindranath * Return Value 334889a36810SAnil Ravindranath * 0 in case of success, otherwise appropriate error code 334989a36810SAnil Ravindranath */ 335089a36810SAnil Ravindranath static long pmcraid_ioctl_driver( 335189a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 335289a36810SAnil Ravindranath unsigned int cmd, 335389a36810SAnil Ravindranath unsigned int buflen, 335489a36810SAnil Ravindranath void __user *user_buffer 335589a36810SAnil Ravindranath ) 335689a36810SAnil Ravindranath { 335789a36810SAnil Ravindranath int rc = -ENOSYS; 335889a36810SAnil Ravindranath 335989a36810SAnil Ravindranath switch (cmd) { 336089a36810SAnil Ravindranath case PMCRAID_IOCTL_RESET_ADAPTER: 336189a36810SAnil Ravindranath pmcraid_reset_bringup(pinstance); 336289a36810SAnil Ravindranath rc = 0; 336389a36810SAnil Ravindranath break; 336489a36810SAnil Ravindranath 336589a36810SAnil Ravindranath default: 336689a36810SAnil Ravindranath break; 336789a36810SAnil Ravindranath } 336889a36810SAnil Ravindranath 336989a36810SAnil Ravindranath return rc; 337089a36810SAnil Ravindranath } 337189a36810SAnil Ravindranath 337289a36810SAnil Ravindranath /** 337389a36810SAnil Ravindranath * pmcraid_check_ioctl_buffer - check for proper access to user buffer 337489a36810SAnil Ravindranath * 337589a36810SAnil Ravindranath * @cmd: ioctl command 337689a36810SAnil Ravindranath * @arg: user buffer 337789a36810SAnil Ravindranath * @hdr: pointer to kernel memory for pmcraid_ioctl_header 337889a36810SAnil Ravindranath * 337989a36810SAnil Ravindranath * Return Value 338089a36810SAnil Ravindranath * negetive error code if there are access issues, otherwise zero. 338189a36810SAnil Ravindranath * Upon success, returns ioctl header copied out of user buffer. 338289a36810SAnil Ravindranath */ 338389a36810SAnil Ravindranath 338489a36810SAnil Ravindranath static int pmcraid_check_ioctl_buffer( 338589a36810SAnil Ravindranath int cmd, 338689a36810SAnil Ravindranath void __user *arg, 338789a36810SAnil Ravindranath struct pmcraid_ioctl_header *hdr 338889a36810SAnil Ravindranath ) 338989a36810SAnil Ravindranath { 3390edb88cefSArnd Bergmann int rc; 339189a36810SAnil Ravindranath 339289a36810SAnil Ravindranath if (copy_from_user(hdr, arg, sizeof(struct pmcraid_ioctl_header))) { 339389a36810SAnil Ravindranath pmcraid_err("couldn't copy ioctl header from user buffer\n"); 339489a36810SAnil Ravindranath return -EFAULT; 339589a36810SAnil Ravindranath } 339689a36810SAnil Ravindranath 339789a36810SAnil Ravindranath /* check for valid driver signature */ 339889a36810SAnil Ravindranath rc = memcmp(hdr->signature, 339989a36810SAnil Ravindranath PMCRAID_IOCTL_SIGNATURE, 340089a36810SAnil Ravindranath sizeof(hdr->signature)); 340189a36810SAnil Ravindranath if (rc) { 340289a36810SAnil Ravindranath pmcraid_err("signature verification failed\n"); 340389a36810SAnil Ravindranath return -EINVAL; 340489a36810SAnil Ravindranath } 340589a36810SAnil Ravindranath 340689a36810SAnil Ravindranath return 0; 340789a36810SAnil Ravindranath } 340889a36810SAnil Ravindranath 34093673b7b0SLee Jones /* 341089a36810SAnil Ravindranath * pmcraid_ioctl - char node ioctl entry point 341189a36810SAnil Ravindranath */ 341289a36810SAnil Ravindranath static long pmcraid_chr_ioctl( 341389a36810SAnil Ravindranath struct file *filep, 341489a36810SAnil Ravindranath unsigned int cmd, 341589a36810SAnil Ravindranath unsigned long arg 341689a36810SAnil Ravindranath ) 341789a36810SAnil Ravindranath { 341889a36810SAnil Ravindranath struct pmcraid_instance *pinstance = NULL; 341989a36810SAnil Ravindranath struct pmcraid_ioctl_header *hdr = NULL; 34203397623bSArnd Bergmann void __user *argp = (void __user *)arg; 342189a36810SAnil Ravindranath int retval = -ENOTTY; 342289a36810SAnil Ravindranath 3423a63ec376SDave Jones hdr = kmalloc(sizeof(struct pmcraid_ioctl_header), GFP_KERNEL); 342489a36810SAnil Ravindranath 342589a36810SAnil Ravindranath if (!hdr) { 34264f91b114SJesper Juhl pmcraid_err("failed to allocate memory for ioctl header\n"); 342789a36810SAnil Ravindranath return -ENOMEM; 342889a36810SAnil Ravindranath } 342989a36810SAnil Ravindranath 34303397623bSArnd Bergmann retval = pmcraid_check_ioctl_buffer(cmd, argp, hdr); 343189a36810SAnil Ravindranath 343289a36810SAnil Ravindranath if (retval) { 343389a36810SAnil Ravindranath pmcraid_info("chr_ioctl: header check failed\n"); 343489a36810SAnil Ravindranath kfree(hdr); 343589a36810SAnil Ravindranath return retval; 343689a36810SAnil Ravindranath } 343789a36810SAnil Ravindranath 3438660bdddbSCyril Jayaprakash pinstance = filep->private_data; 343989a36810SAnil Ravindranath 344089a36810SAnil Ravindranath if (!pinstance) { 344189a36810SAnil Ravindranath pmcraid_info("adapter instance is not found\n"); 344289a36810SAnil Ravindranath kfree(hdr); 344389a36810SAnil Ravindranath return -ENOTTY; 344489a36810SAnil Ravindranath } 344589a36810SAnil Ravindranath 344689a36810SAnil Ravindranath switch (_IOC_TYPE(cmd)) { 344789a36810SAnil Ravindranath 344889a36810SAnil Ravindranath case PMCRAID_DRIVER_IOCTL: 344989a36810SAnil Ravindranath arg += sizeof(struct pmcraid_ioctl_header); 34503397623bSArnd Bergmann retval = pmcraid_ioctl_driver(pinstance, cmd, 34513397623bSArnd Bergmann hdr->buffer_length, argp); 345289a36810SAnil Ravindranath break; 345389a36810SAnil Ravindranath 345489a36810SAnil Ravindranath default: 345589a36810SAnil Ravindranath retval = -ENOTTY; 345689a36810SAnil Ravindranath break; 345789a36810SAnil Ravindranath } 345889a36810SAnil Ravindranath 345989a36810SAnil Ravindranath kfree(hdr); 346089a36810SAnil Ravindranath 346189a36810SAnil Ravindranath return retval; 346289a36810SAnil Ravindranath } 346389a36810SAnil Ravindranath 34643673b7b0SLee Jones /* 346589a36810SAnil Ravindranath * File operations structure for management interface 346689a36810SAnil Ravindranath */ 346789a36810SAnil Ravindranath static const struct file_operations pmcraid_fops = { 346889a36810SAnil Ravindranath .owner = THIS_MODULE, 346989a36810SAnil Ravindranath .open = pmcraid_chr_open, 347089a36810SAnil Ravindranath .fasync = pmcraid_chr_fasync, 347189a36810SAnil Ravindranath .unlocked_ioctl = pmcraid_chr_ioctl, 34721832f2d8SArnd Bergmann .compat_ioctl = compat_ptr_ioctl, 34736038f373SArnd Bergmann .llseek = noop_llseek, 347489a36810SAnil Ravindranath }; 347589a36810SAnil Ravindranath 347689a36810SAnil Ravindranath 347789a36810SAnil Ravindranath 347889a36810SAnil Ravindranath 347989a36810SAnil Ravindranath /** 348089a36810SAnil Ravindranath * pmcraid_show_log_level - Display adapter's error logging level 348189a36810SAnil Ravindranath * @dev: class device struct 34823673b7b0SLee Jones * @attr: unused 348389a36810SAnil Ravindranath * @buf: buffer 348489a36810SAnil Ravindranath * 348589a36810SAnil Ravindranath * Return value: 348689a36810SAnil Ravindranath * number of bytes printed to buffer 348789a36810SAnil Ravindranath */ 348889a36810SAnil Ravindranath static ssize_t pmcraid_show_log_level( 348989a36810SAnil Ravindranath struct device *dev, 349089a36810SAnil Ravindranath struct device_attribute *attr, 349189a36810SAnil Ravindranath char *buf) 349289a36810SAnil Ravindranath { 349389a36810SAnil Ravindranath struct Scsi_Host *shost = class_to_shost(dev); 349489a36810SAnil Ravindranath struct pmcraid_instance *pinstance = 349589a36810SAnil Ravindranath (struct pmcraid_instance *)shost->hostdata; 349689a36810SAnil Ravindranath return snprintf(buf, PAGE_SIZE, "%d\n", pinstance->current_log_level); 349789a36810SAnil Ravindranath } 349889a36810SAnil Ravindranath 349989a36810SAnil Ravindranath /** 350089a36810SAnil Ravindranath * pmcraid_store_log_level - Change the adapter's error logging level 350189a36810SAnil Ravindranath * @dev: class device struct 35023673b7b0SLee Jones * @attr: unused 350389a36810SAnil Ravindranath * @buf: buffer 350489a36810SAnil Ravindranath * @count: not used 350589a36810SAnil Ravindranath * 350689a36810SAnil Ravindranath * Return value: 350789a36810SAnil Ravindranath * number of bytes printed to buffer 350889a36810SAnil Ravindranath */ 350989a36810SAnil Ravindranath static ssize_t pmcraid_store_log_level( 351089a36810SAnil Ravindranath struct device *dev, 351189a36810SAnil Ravindranath struct device_attribute *attr, 351289a36810SAnil Ravindranath const char *buf, 351389a36810SAnil Ravindranath size_t count 351489a36810SAnil Ravindranath ) 351589a36810SAnil Ravindranath { 351689a36810SAnil Ravindranath struct Scsi_Host *shost; 351789a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 3518f7c65af5SDaniel Walter u8 val; 351989a36810SAnil Ravindranath 3520f7c65af5SDaniel Walter if (kstrtou8(buf, 10, &val)) 352189a36810SAnil Ravindranath return -EINVAL; 352289a36810SAnil Ravindranath /* log-level should be from 0 to 2 */ 352389a36810SAnil Ravindranath if (val > 2) 352489a36810SAnil Ravindranath return -EINVAL; 352589a36810SAnil Ravindranath 352689a36810SAnil Ravindranath shost = class_to_shost(dev); 352789a36810SAnil Ravindranath pinstance = (struct pmcraid_instance *)shost->hostdata; 352889a36810SAnil Ravindranath pinstance->current_log_level = val; 352989a36810SAnil Ravindranath 353089a36810SAnil Ravindranath return strlen(buf); 353189a36810SAnil Ravindranath } 353289a36810SAnil Ravindranath 353389a36810SAnil Ravindranath static struct device_attribute pmcraid_log_level_attr = { 353489a36810SAnil Ravindranath .attr = { 353589a36810SAnil Ravindranath .name = "log_level", 353689a36810SAnil Ravindranath .mode = S_IRUGO | S_IWUSR, 353789a36810SAnil Ravindranath }, 353889a36810SAnil Ravindranath .show = pmcraid_show_log_level, 353989a36810SAnil Ravindranath .store = pmcraid_store_log_level, 354089a36810SAnil Ravindranath }; 354189a36810SAnil Ravindranath 354289a36810SAnil Ravindranath /** 354389a36810SAnil Ravindranath * pmcraid_show_drv_version - Display driver version 354489a36810SAnil Ravindranath * @dev: class device struct 35453673b7b0SLee Jones * @attr: unused 354689a36810SAnil Ravindranath * @buf: buffer 354789a36810SAnil Ravindranath * 354889a36810SAnil Ravindranath * Return value: 354989a36810SAnil Ravindranath * number of bytes printed to buffer 355089a36810SAnil Ravindranath */ 355189a36810SAnil Ravindranath static ssize_t pmcraid_show_drv_version( 355289a36810SAnil Ravindranath struct device *dev, 355389a36810SAnil Ravindranath struct device_attribute *attr, 355489a36810SAnil Ravindranath char *buf 355589a36810SAnil Ravindranath ) 355689a36810SAnil Ravindranath { 3557a1b66665SMichal Marek return snprintf(buf, PAGE_SIZE, "version: %s\n", 3558a1b66665SMichal Marek PMCRAID_DRIVER_VERSION); 355989a36810SAnil Ravindranath } 356089a36810SAnil Ravindranath 356189a36810SAnil Ravindranath static struct device_attribute pmcraid_driver_version_attr = { 356289a36810SAnil Ravindranath .attr = { 356389a36810SAnil Ravindranath .name = "drv_version", 356489a36810SAnil Ravindranath .mode = S_IRUGO, 356589a36810SAnil Ravindranath }, 356689a36810SAnil Ravindranath .show = pmcraid_show_drv_version, 356789a36810SAnil Ravindranath }; 356889a36810SAnil Ravindranath 356989a36810SAnil Ravindranath /** 3570a364a147SLee Jones * pmcraid_show_adapter_id - Display driver assigned adapter id 357189a36810SAnil Ravindranath * @dev: class device struct 35723673b7b0SLee Jones * @attr: unused 357389a36810SAnil Ravindranath * @buf: buffer 357489a36810SAnil Ravindranath * 357589a36810SAnil Ravindranath * Return value: 357689a36810SAnil Ravindranath * number of bytes printed to buffer 357789a36810SAnil Ravindranath */ 357889a36810SAnil Ravindranath static ssize_t pmcraid_show_adapter_id( 357989a36810SAnil Ravindranath struct device *dev, 358089a36810SAnil Ravindranath struct device_attribute *attr, 358189a36810SAnil Ravindranath char *buf 358289a36810SAnil Ravindranath ) 358389a36810SAnil Ravindranath { 358489a36810SAnil Ravindranath struct Scsi_Host *shost = class_to_shost(dev); 358589a36810SAnil Ravindranath struct pmcraid_instance *pinstance = 358689a36810SAnil Ravindranath (struct pmcraid_instance *)shost->hostdata; 358789a36810SAnil Ravindranath u32 adapter_id = (pinstance->pdev->bus->number << 8) | 358889a36810SAnil Ravindranath pinstance->pdev->devfn; 358989a36810SAnil Ravindranath u32 aen_group = pmcraid_event_family.id; 359089a36810SAnil Ravindranath 359189a36810SAnil Ravindranath return snprintf(buf, PAGE_SIZE, 359289a36810SAnil Ravindranath "adapter id: %d\nminor: %d\naen group: %d\n", 359389a36810SAnil Ravindranath adapter_id, MINOR(pinstance->cdev.dev), aen_group); 359489a36810SAnil Ravindranath } 359589a36810SAnil Ravindranath 359689a36810SAnil Ravindranath static struct device_attribute pmcraid_adapter_id_attr = { 359789a36810SAnil Ravindranath .attr = { 359889a36810SAnil Ravindranath .name = "adapter_id", 35995a0ccb6bSAlan .mode = S_IRUGO, 360089a36810SAnil Ravindranath }, 360189a36810SAnil Ravindranath .show = pmcraid_show_adapter_id, 360289a36810SAnil Ravindranath }; 360389a36810SAnil Ravindranath 3604646bed7eSBart Van Assche static struct attribute *pmcraid_host_attrs[] = { 3605646bed7eSBart Van Assche &pmcraid_log_level_attr.attr, 3606646bed7eSBart Van Assche &pmcraid_driver_version_attr.attr, 3607646bed7eSBart Van Assche &pmcraid_adapter_id_attr.attr, 360889a36810SAnil Ravindranath NULL, 360989a36810SAnil Ravindranath }; 361089a36810SAnil Ravindranath 3611646bed7eSBart Van Assche ATTRIBUTE_GROUPS(pmcraid_host); 361289a36810SAnil Ravindranath 361389a36810SAnil Ravindranath /* host template structure for pmcraid driver */ 361489a36810SAnil Ravindranath static struct scsi_host_template pmcraid_host_template = { 361589a36810SAnil Ravindranath .module = THIS_MODULE, 361689a36810SAnil Ravindranath .name = PMCRAID_DRIVER_NAME, 361789a36810SAnil Ravindranath .queuecommand = pmcraid_queuecommand, 361889a36810SAnil Ravindranath .eh_abort_handler = pmcraid_eh_abort_handler, 361989a36810SAnil Ravindranath .eh_bus_reset_handler = pmcraid_eh_bus_reset_handler, 362089a36810SAnil Ravindranath .eh_target_reset_handler = pmcraid_eh_target_reset_handler, 362189a36810SAnil Ravindranath .eh_device_reset_handler = pmcraid_eh_device_reset_handler, 362289a36810SAnil Ravindranath .eh_host_reset_handler = pmcraid_eh_host_reset_handler, 362389a36810SAnil Ravindranath 362489a36810SAnil Ravindranath .slave_alloc = pmcraid_slave_alloc, 362589a36810SAnil Ravindranath .slave_configure = pmcraid_slave_configure, 362689a36810SAnil Ravindranath .slave_destroy = pmcraid_slave_destroy, 362789a36810SAnil Ravindranath .change_queue_depth = pmcraid_change_queue_depth, 362889a36810SAnil Ravindranath .can_queue = PMCRAID_MAX_IO_CMD, 362989a36810SAnil Ravindranath .this_id = -1, 363089a36810SAnil Ravindranath .sg_tablesize = PMCRAID_MAX_IOADLS, 363189a36810SAnil Ravindranath .max_sectors = PMCRAID_IOA_MAX_SECTORS, 363254b2b50cSMartin K. Petersen .no_write_same = 1, 363389a36810SAnil Ravindranath .cmd_per_lun = PMCRAID_MAX_CMD_PER_LUN, 3634646bed7eSBart Van Assche .shost_groups = pmcraid_host_groups, 36352ecb204dSChristoph Hellwig .proc_name = PMCRAID_DRIVER_NAME, 363689a36810SAnil Ravindranath }; 363789a36810SAnil Ravindranath 3638c20c4267SAnil Ravindranath /* 3639c20c4267SAnil Ravindranath * pmcraid_isr_msix - implements MSI-X interrupt handling routine 3640c20c4267SAnil Ravindranath * @irq: interrupt vector number 3641c20c4267SAnil Ravindranath * @dev_id: pointer hrrq_vector 364289a36810SAnil Ravindranath * 364389a36810SAnil Ravindranath * Return Value 3644c20c4267SAnil Ravindranath * IRQ_HANDLED if interrupt is handled or IRQ_NONE if ignored 364589a36810SAnil Ravindranath */ 364689a36810SAnil Ravindranath 3647c20c4267SAnil Ravindranath static irqreturn_t pmcraid_isr_msix(int irq, void *dev_id) 3648c20c4267SAnil Ravindranath { 3649c20c4267SAnil Ravindranath struct pmcraid_isr_param *hrrq_vector; 3650c20c4267SAnil Ravindranath struct pmcraid_instance *pinstance; 3651c20c4267SAnil Ravindranath unsigned long lock_flags; 3652c20c4267SAnil Ravindranath u32 intrs_val; 3653c20c4267SAnil Ravindranath int hrrq_id; 3654c20c4267SAnil Ravindranath 3655c20c4267SAnil Ravindranath hrrq_vector = (struct pmcraid_isr_param *)dev_id; 3656c20c4267SAnil Ravindranath hrrq_id = hrrq_vector->hrrq_id; 3657c20c4267SAnil Ravindranath pinstance = hrrq_vector->drv_inst; 3658c20c4267SAnil Ravindranath 3659c20c4267SAnil Ravindranath if (!hrrq_id) { 3660c20c4267SAnil Ravindranath /* Read the interrupt */ 3661c20c4267SAnil Ravindranath intrs_val = pmcraid_read_interrupts(pinstance); 3662c20c4267SAnil Ravindranath if (intrs_val && 3663c20c4267SAnil Ravindranath ((ioread32(pinstance->int_regs.host_ioa_interrupt_reg) 3664c20c4267SAnil Ravindranath & DOORBELL_INTR_MSIX_CLR) == 0)) { 3665c20c4267SAnil Ravindranath /* Any error interrupts including unit_check, 3666c20c4267SAnil Ravindranath * initiate IOA reset.In case of unit check indicate 3667c20c4267SAnil Ravindranath * to reset_sequence that IOA unit checked and prepare 3668c20c4267SAnil Ravindranath * for a dump during reset sequence 3669c20c4267SAnil Ravindranath */ 3670c20c4267SAnil Ravindranath if (intrs_val & PMCRAID_ERROR_INTERRUPTS) { 3671c20c4267SAnil Ravindranath if (intrs_val & INTRS_IOA_UNIT_CHECK) 3672c20c4267SAnil Ravindranath pinstance->ioa_unit_check = 1; 3673c20c4267SAnil Ravindranath 3674c20c4267SAnil Ravindranath pmcraid_err("ISR: error interrupts: %x \ 3675c20c4267SAnil Ravindranath initiating reset\n", intrs_val); 3676c20c4267SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, 3677c20c4267SAnil Ravindranath lock_flags); 3678c20c4267SAnil Ravindranath pmcraid_initiate_reset(pinstance); 3679c20c4267SAnil Ravindranath spin_unlock_irqrestore( 3680c20c4267SAnil Ravindranath pinstance->host->host_lock, 3681c20c4267SAnil Ravindranath lock_flags); 3682c20c4267SAnil Ravindranath } 3683c20c4267SAnil Ravindranath /* If interrupt was as part of the ioa initialization, 3684c20c4267SAnil Ravindranath * clear it. Delete the timer and wakeup the 3685c20c4267SAnil Ravindranath * reset engine to proceed with reset sequence 3686c20c4267SAnil Ravindranath */ 3687c20c4267SAnil Ravindranath if (intrs_val & INTRS_TRANSITION_TO_OPERATIONAL) 3688c20c4267SAnil Ravindranath pmcraid_clr_trans_op(pinstance); 3689c20c4267SAnil Ravindranath 3690c20c4267SAnil Ravindranath /* Clear the interrupt register by writing 3691c20c4267SAnil Ravindranath * to host to ioa doorbell. Once done 3692c20c4267SAnil Ravindranath * FW will clear the interrupt. 3693c20c4267SAnil Ravindranath */ 3694c20c4267SAnil Ravindranath iowrite32(DOORBELL_INTR_MSIX_CLR, 3695c20c4267SAnil Ravindranath pinstance->int_regs.host_ioa_interrupt_reg); 3696c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.host_ioa_interrupt_reg); 3697c20c4267SAnil Ravindranath 3698c20c4267SAnil Ravindranath 3699c20c4267SAnil Ravindranath } 3700c20c4267SAnil Ravindranath } 3701c20c4267SAnil Ravindranath 370289a36810SAnil Ravindranath tasklet_schedule(&(pinstance->isr_tasklet[hrrq_id])); 3703c20c4267SAnil Ravindranath 3704c20c4267SAnil Ravindranath return IRQ_HANDLED; 370589a36810SAnil Ravindranath } 370689a36810SAnil Ravindranath 370789a36810SAnil Ravindranath /** 3708c20c4267SAnil Ravindranath * pmcraid_isr - implements legacy interrupt handling routine 370989a36810SAnil Ravindranath * 371089a36810SAnil Ravindranath * @irq: interrupt vector number 371189a36810SAnil Ravindranath * @dev_id: pointer hrrq_vector 371289a36810SAnil Ravindranath * 371389a36810SAnil Ravindranath * Return Value 371489a36810SAnil Ravindranath * IRQ_HANDLED if interrupt is handled or IRQ_NONE if ignored 371589a36810SAnil Ravindranath */ 371689a36810SAnil Ravindranath static irqreturn_t pmcraid_isr(int irq, void *dev_id) 371789a36810SAnil Ravindranath { 371889a36810SAnil Ravindranath struct pmcraid_isr_param *hrrq_vector; 371989a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 372089a36810SAnil Ravindranath u32 intrs; 3721c20c4267SAnil Ravindranath unsigned long lock_flags; 3722c20c4267SAnil Ravindranath int hrrq_id = 0; 372389a36810SAnil Ravindranath 372489a36810SAnil Ravindranath /* In case of legacy interrupt mode where interrupts are shared across 372589a36810SAnil Ravindranath * isrs, it may be possible that the current interrupt is not from IOA 372689a36810SAnil Ravindranath */ 372789a36810SAnil Ravindranath if (!dev_id) { 372889a36810SAnil Ravindranath printk(KERN_INFO "%s(): NULL host pointer\n", __func__); 372989a36810SAnil Ravindranath return IRQ_NONE; 373089a36810SAnil Ravindranath } 373189a36810SAnil Ravindranath hrrq_vector = (struct pmcraid_isr_param *)dev_id; 373289a36810SAnil Ravindranath pinstance = hrrq_vector->drv_inst; 373389a36810SAnil Ravindranath 373489a36810SAnil Ravindranath intrs = pmcraid_read_interrupts(pinstance); 373589a36810SAnil Ravindranath 3736c20c4267SAnil Ravindranath if (unlikely((intrs & PMCRAID_PCI_INTERRUPTS) == 0)) 373789a36810SAnil Ravindranath return IRQ_NONE; 373889a36810SAnil Ravindranath 373989a36810SAnil Ravindranath /* Any error interrupts including unit_check, initiate IOA reset. 374089a36810SAnil Ravindranath * In case of unit check indicate to reset_sequence that IOA unit 374189a36810SAnil Ravindranath * checked and prepare for a dump during reset sequence 374289a36810SAnil Ravindranath */ 374389a36810SAnil Ravindranath if (intrs & PMCRAID_ERROR_INTERRUPTS) { 374489a36810SAnil Ravindranath 374589a36810SAnil Ravindranath if (intrs & INTRS_IOA_UNIT_CHECK) 374689a36810SAnil Ravindranath pinstance->ioa_unit_check = 1; 374789a36810SAnil Ravindranath 374889a36810SAnil Ravindranath iowrite32(intrs, 374989a36810SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_clr_reg); 375089a36810SAnil Ravindranath pmcraid_err("ISR: error interrupts: %x initiating reset\n", 375189a36810SAnil Ravindranath intrs); 3752c20c4267SAnil Ravindranath intrs = ioread32( 3753c20c4267SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_clr_reg); 3754c20c4267SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, lock_flags); 375589a36810SAnil Ravindranath pmcraid_initiate_reset(pinstance); 375689a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); 3757c20c4267SAnil Ravindranath } else { 3758c20c4267SAnil Ravindranath /* If interrupt was as part of the ioa initialization, 3759c20c4267SAnil Ravindranath * clear. Delete the timer and wakeup the 3760c20c4267SAnil Ravindranath * reset engine to proceed with reset sequence 3761c20c4267SAnil Ravindranath */ 3762c20c4267SAnil Ravindranath if (intrs & INTRS_TRANSITION_TO_OPERATIONAL) { 3763c20c4267SAnil Ravindranath pmcraid_clr_trans_op(pinstance); 3764c20c4267SAnil Ravindranath } else { 3765c20c4267SAnil Ravindranath iowrite32(intrs, 3766c20c4267SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_clr_reg); 3767c20c4267SAnil Ravindranath ioread32( 3768c20c4267SAnil Ravindranath pinstance->int_regs.ioa_host_interrupt_clr_reg); 3769c20c4267SAnil Ravindranath 3770c20c4267SAnil Ravindranath tasklet_schedule( 3771c20c4267SAnil Ravindranath &(pinstance->isr_tasklet[hrrq_id])); 3772c20c4267SAnil Ravindranath } 3773c20c4267SAnil Ravindranath } 377489a36810SAnil Ravindranath 377589a36810SAnil Ravindranath return IRQ_HANDLED; 377689a36810SAnil Ravindranath } 377789a36810SAnil Ravindranath 377889a36810SAnil Ravindranath 377989a36810SAnil Ravindranath /** 378089a36810SAnil Ravindranath * pmcraid_worker_function - worker thread function 378189a36810SAnil Ravindranath * 378289a36810SAnil Ravindranath * @workp: pointer to struct work queue 378389a36810SAnil Ravindranath * 378489a36810SAnil Ravindranath * Return Value 378589a36810SAnil Ravindranath * None 378689a36810SAnil Ravindranath */ 378789a36810SAnil Ravindranath 378889a36810SAnil Ravindranath static void pmcraid_worker_function(struct work_struct *workp) 378989a36810SAnil Ravindranath { 379089a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 379189a36810SAnil Ravindranath struct pmcraid_resource_entry *res; 379289a36810SAnil Ravindranath struct pmcraid_resource_entry *temp; 379389a36810SAnil Ravindranath struct scsi_device *sdev; 379489a36810SAnil Ravindranath unsigned long lock_flags; 379589a36810SAnil Ravindranath unsigned long host_lock_flags; 3796c20c4267SAnil Ravindranath u16 fw_version; 379789a36810SAnil Ravindranath u8 bus, target, lun; 379889a36810SAnil Ravindranath 379989a36810SAnil Ravindranath pinstance = container_of(workp, struct pmcraid_instance, worker_q); 380089a36810SAnil Ravindranath /* add resources only after host is added into system */ 380189a36810SAnil Ravindranath if (!atomic_read(&pinstance->expose_resources)) 380289a36810SAnil Ravindranath return; 380389a36810SAnil Ravindranath 3804c20c4267SAnil Ravindranath fw_version = be16_to_cpu(pinstance->inq_data->fw_version); 3805c20c4267SAnil Ravindranath 380689a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->resource_lock, lock_flags); 380789a36810SAnil Ravindranath list_for_each_entry_safe(res, temp, &pinstance->used_res_q, queue) { 380889a36810SAnil Ravindranath 380989a36810SAnil Ravindranath if (res->change_detected == RES_CHANGE_DEL && res->scsi_dev) { 381089a36810SAnil Ravindranath sdev = res->scsi_dev; 381189a36810SAnil Ravindranath 381289a36810SAnil Ravindranath /* host_lock must be held before calling 381389a36810SAnil Ravindranath * scsi_device_get 381489a36810SAnil Ravindranath */ 381589a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, 381689a36810SAnil Ravindranath host_lock_flags); 381789a36810SAnil Ravindranath if (!scsi_device_get(sdev)) { 381889a36810SAnil Ravindranath spin_unlock_irqrestore( 381989a36810SAnil Ravindranath pinstance->host->host_lock, 382089a36810SAnil Ravindranath host_lock_flags); 382189a36810SAnil Ravindranath pmcraid_info("deleting %x from midlayer\n", 382289a36810SAnil Ravindranath res->cfg_entry.resource_address); 382389a36810SAnil Ravindranath list_move_tail(&res->queue, 382489a36810SAnil Ravindranath &pinstance->free_res_q); 382589a36810SAnil Ravindranath spin_unlock_irqrestore( 382689a36810SAnil Ravindranath &pinstance->resource_lock, 382789a36810SAnil Ravindranath lock_flags); 382889a36810SAnil Ravindranath scsi_remove_device(sdev); 382989a36810SAnil Ravindranath scsi_device_put(sdev); 383089a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->resource_lock, 383189a36810SAnil Ravindranath lock_flags); 383289a36810SAnil Ravindranath res->change_detected = 0; 383389a36810SAnil Ravindranath } else { 383489a36810SAnil Ravindranath spin_unlock_irqrestore( 383589a36810SAnil Ravindranath pinstance->host->host_lock, 383689a36810SAnil Ravindranath host_lock_flags); 383789a36810SAnil Ravindranath } 383889a36810SAnil Ravindranath } 383989a36810SAnil Ravindranath } 384089a36810SAnil Ravindranath 384189a36810SAnil Ravindranath list_for_each_entry(res, &pinstance->used_res_q, queue) { 384289a36810SAnil Ravindranath 384389a36810SAnil Ravindranath if (res->change_detected == RES_CHANGE_ADD) { 384489a36810SAnil Ravindranath 3845c20c4267SAnil Ravindranath if (!pmcraid_expose_resource(fw_version, 3846c20c4267SAnil Ravindranath &res->cfg_entry)) 384789a36810SAnil Ravindranath continue; 384889a36810SAnil Ravindranath 384989a36810SAnil Ravindranath if (RES_IS_VSET(res->cfg_entry)) { 385089a36810SAnil Ravindranath bus = PMCRAID_VSET_BUS_ID; 3851c20c4267SAnil Ravindranath if (fw_version <= PMCRAID_FW_VERSION_1) 385289a36810SAnil Ravindranath target = res->cfg_entry.unique_flags1; 3853c20c4267SAnil Ravindranath else 385445c80be6SArnd Bergmann target = le16_to_cpu(res->cfg_entry.array_id) & 0xFF; 385589a36810SAnil Ravindranath lun = PMCRAID_VSET_LUN_ID; 385689a36810SAnil Ravindranath } else { 385789a36810SAnil Ravindranath bus = PMCRAID_PHYS_BUS_ID; 385889a36810SAnil Ravindranath target = 385989a36810SAnil Ravindranath RES_TARGET( 386089a36810SAnil Ravindranath res->cfg_entry.resource_address); 386189a36810SAnil Ravindranath lun = RES_LUN(res->cfg_entry.resource_address); 386289a36810SAnil Ravindranath } 386389a36810SAnil Ravindranath 386489a36810SAnil Ravindranath res->change_detected = 0; 386589a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, 386689a36810SAnil Ravindranath lock_flags); 386789a36810SAnil Ravindranath scsi_add_device(pinstance->host, bus, target, lun); 386889a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->resource_lock, 386989a36810SAnil Ravindranath lock_flags); 387089a36810SAnil Ravindranath } 387189a36810SAnil Ravindranath } 387289a36810SAnil Ravindranath 387389a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); 387489a36810SAnil Ravindranath } 387589a36810SAnil Ravindranath 387689a36810SAnil Ravindranath /** 387789a36810SAnil Ravindranath * pmcraid_tasklet_function - Tasklet function 387889a36810SAnil Ravindranath * 387989a36810SAnil Ravindranath * @instance: pointer to msix param structure 388089a36810SAnil Ravindranath * 388189a36810SAnil Ravindranath * Return Value 388289a36810SAnil Ravindranath * None 388389a36810SAnil Ravindranath */ 3884c20c4267SAnil Ravindranath static void pmcraid_tasklet_function(unsigned long instance) 388589a36810SAnil Ravindranath { 388689a36810SAnil Ravindranath struct pmcraid_isr_param *hrrq_vector; 388789a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 388889a36810SAnil Ravindranath unsigned long hrrq_lock_flags; 388989a36810SAnil Ravindranath unsigned long pending_lock_flags; 389089a36810SAnil Ravindranath unsigned long host_lock_flags; 389189a36810SAnil Ravindranath spinlock_t *lockp; /* hrrq buffer lock */ 389289a36810SAnil Ravindranath int id; 389345c80be6SArnd Bergmann u32 resp; 389489a36810SAnil Ravindranath 389589a36810SAnil Ravindranath hrrq_vector = (struct pmcraid_isr_param *)instance; 389689a36810SAnil Ravindranath pinstance = hrrq_vector->drv_inst; 389789a36810SAnil Ravindranath id = hrrq_vector->hrrq_id; 389889a36810SAnil Ravindranath lockp = &(pinstance->hrrq_lock[id]); 389989a36810SAnil Ravindranath 390089a36810SAnil Ravindranath /* loop through each of the commands responded by IOA. Each HRRQ buf is 390189a36810SAnil Ravindranath * protected by its own lock. Traversals must be done within this lock 390289a36810SAnil Ravindranath * as there may be multiple tasklets running on multiple CPUs. Note 390389a36810SAnil Ravindranath * that the lock is held just for picking up the response handle and 390489a36810SAnil Ravindranath * manipulating hrrq_curr/toggle_bit values. 390589a36810SAnil Ravindranath */ 390689a36810SAnil Ravindranath spin_lock_irqsave(lockp, hrrq_lock_flags); 390789a36810SAnil Ravindranath 390889a36810SAnil Ravindranath resp = le32_to_cpu(*(pinstance->hrrq_curr[id])); 390989a36810SAnil Ravindranath 391089a36810SAnil Ravindranath while ((resp & HRRQ_TOGGLE_BIT) == 391189a36810SAnil Ravindranath pinstance->host_toggle_bit[id]) { 391289a36810SAnil Ravindranath 391389a36810SAnil Ravindranath int cmd_index = resp >> 2; 391489a36810SAnil Ravindranath struct pmcraid_cmd *cmd = NULL; 391589a36810SAnil Ravindranath 391689a36810SAnil Ravindranath if (pinstance->hrrq_curr[id] < pinstance->hrrq_end[id]) { 391789a36810SAnil Ravindranath pinstance->hrrq_curr[id]++; 391889a36810SAnil Ravindranath } else { 391989a36810SAnil Ravindranath pinstance->hrrq_curr[id] = pinstance->hrrq_start[id]; 392089a36810SAnil Ravindranath pinstance->host_toggle_bit[id] ^= 1u; 392189a36810SAnil Ravindranath } 392289a36810SAnil Ravindranath 3923c20c4267SAnil Ravindranath if (cmd_index >= PMCRAID_MAX_CMD) { 3924c20c4267SAnil Ravindranath /* In case of invalid response handle, log message */ 3925c20c4267SAnil Ravindranath pmcraid_err("Invalid response handle %d\n", cmd_index); 3926c20c4267SAnil Ravindranath resp = le32_to_cpu(*(pinstance->hrrq_curr[id])); 3927c20c4267SAnil Ravindranath continue; 3928c20c4267SAnil Ravindranath } 3929c20c4267SAnil Ravindranath 3930c20c4267SAnil Ravindranath cmd = pinstance->cmd_list[cmd_index]; 393189a36810SAnil Ravindranath spin_unlock_irqrestore(lockp, hrrq_lock_flags); 393289a36810SAnil Ravindranath 393389a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->pending_pool_lock, 393489a36810SAnil Ravindranath pending_lock_flags); 393589a36810SAnil Ravindranath list_del(&cmd->free_list); 393689a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->pending_pool_lock, 393789a36810SAnil Ravindranath pending_lock_flags); 393889a36810SAnil Ravindranath del_timer(&cmd->timer); 393989a36810SAnil Ravindranath atomic_dec(&pinstance->outstanding_cmds); 394089a36810SAnil Ravindranath 394189a36810SAnil Ravindranath if (cmd->cmd_done == pmcraid_ioa_reset) { 394289a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, 394389a36810SAnil Ravindranath host_lock_flags); 394489a36810SAnil Ravindranath cmd->cmd_done(cmd); 394589a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, 394689a36810SAnil Ravindranath host_lock_flags); 394789a36810SAnil Ravindranath } else if (cmd->cmd_done != NULL) { 394889a36810SAnil Ravindranath cmd->cmd_done(cmd); 394989a36810SAnil Ravindranath } 395089a36810SAnil Ravindranath /* loop over until we are done with all responses */ 395189a36810SAnil Ravindranath spin_lock_irqsave(lockp, hrrq_lock_flags); 395289a36810SAnil Ravindranath resp = le32_to_cpu(*(pinstance->hrrq_curr[id])); 395389a36810SAnil Ravindranath } 395489a36810SAnil Ravindranath 395589a36810SAnil Ravindranath spin_unlock_irqrestore(lockp, hrrq_lock_flags); 395689a36810SAnil Ravindranath } 395789a36810SAnil Ravindranath 395889a36810SAnil Ravindranath /** 395989a36810SAnil Ravindranath * pmcraid_unregister_interrupt_handler - de-register interrupts handlers 396089a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 396189a36810SAnil Ravindranath * 396289a36810SAnil Ravindranath * This routine un-registers registered interrupt handler and 396389a36810SAnil Ravindranath * also frees irqs/vectors. 396489a36810SAnil Ravindranath * 396589a36810SAnil Ravindranath * Retun Value 396689a36810SAnil Ravindranath * None 396789a36810SAnil Ravindranath */ 396889a36810SAnil Ravindranath static 396989a36810SAnil Ravindranath void pmcraid_unregister_interrupt_handler(struct pmcraid_instance *pinstance) 397089a36810SAnil Ravindranath { 3971eab5c150SChristoph Hellwig struct pci_dev *pdev = pinstance->pdev; 3972c20c4267SAnil Ravindranath int i; 3973c20c4267SAnil Ravindranath 3974c20c4267SAnil Ravindranath for (i = 0; i < pinstance->num_hrrq; i++) 3975eab5c150SChristoph Hellwig free_irq(pci_irq_vector(pdev, i), &pinstance->hrrq_vector[i]); 3976c20c4267SAnil Ravindranath 3977c20c4267SAnil Ravindranath pinstance->interrupt_mode = 0; 3978eab5c150SChristoph Hellwig pci_free_irq_vectors(pdev); 397989a36810SAnil Ravindranath } 398089a36810SAnil Ravindranath 398189a36810SAnil Ravindranath /** 398289a36810SAnil Ravindranath * pmcraid_register_interrupt_handler - registers interrupt handler 398389a36810SAnil Ravindranath * @pinstance: pointer to per-adapter instance structure 398489a36810SAnil Ravindranath * 398589a36810SAnil Ravindranath * Return Value 398689a36810SAnil Ravindranath * 0 on success, non-zero error code otherwise. 398789a36810SAnil Ravindranath */ 398889a36810SAnil Ravindranath static int 398989a36810SAnil Ravindranath pmcraid_register_interrupt_handler(struct pmcraid_instance *pinstance) 399089a36810SAnil Ravindranath { 399189a36810SAnil Ravindranath struct pci_dev *pdev = pinstance->pdev; 3992eab5c150SChristoph Hellwig unsigned int irq_flag = PCI_IRQ_LEGACY, flag; 3993eab5c150SChristoph Hellwig int num_hrrq, rc, i; 3994eab5c150SChristoph Hellwig irq_handler_t isr; 399589a36810SAnil Ravindranath 3996eab5c150SChristoph Hellwig if (pmcraid_enable_msix) 3997eab5c150SChristoph Hellwig irq_flag |= PCI_IRQ_MSIX; 3998c20c4267SAnil Ravindranath 3999eab5c150SChristoph Hellwig num_hrrq = pci_alloc_irq_vectors(pdev, 1, PMCRAID_NUM_MSIX_VECTORS, 4000eab5c150SChristoph Hellwig irq_flag); 4001c01a8bc0SAlexander Gordeev if (num_hrrq < 0) 4002eab5c150SChristoph Hellwig return num_hrrq; 4003eab5c150SChristoph Hellwig 4004eab5c150SChristoph Hellwig if (pdev->msix_enabled) { 4005eab5c150SChristoph Hellwig flag = 0; 4006eab5c150SChristoph Hellwig isr = pmcraid_isr_msix; 4007eab5c150SChristoph Hellwig } else { 4008eab5c150SChristoph Hellwig flag = IRQF_SHARED; 4009eab5c150SChristoph Hellwig isr = pmcraid_isr; 4010eab5c150SChristoph Hellwig } 4011c20c4267SAnil Ravindranath 4012c20c4267SAnil Ravindranath for (i = 0; i < num_hrrq; i++) { 4013eab5c150SChristoph Hellwig struct pmcraid_isr_param *vec = &pinstance->hrrq_vector[i]; 4014c20c4267SAnil Ravindranath 4015eab5c150SChristoph Hellwig vec->hrrq_id = i; 4016eab5c150SChristoph Hellwig vec->drv_inst = pinstance; 4017eab5c150SChristoph Hellwig rc = request_irq(pci_irq_vector(pdev, i), isr, flag, 4018eab5c150SChristoph Hellwig PMCRAID_DRIVER_NAME, vec); 4019eab5c150SChristoph Hellwig if (rc) 4020eab5c150SChristoph Hellwig goto out_unwind; 4021c20c4267SAnil Ravindranath } 4022c20c4267SAnil Ravindranath 4023c20c4267SAnil Ravindranath pinstance->num_hrrq = num_hrrq; 4024eab5c150SChristoph Hellwig if (pdev->msix_enabled) { 4025c20c4267SAnil Ravindranath pinstance->interrupt_mode = 1; 4026c20c4267SAnil Ravindranath iowrite32(DOORBELL_INTR_MODE_MSIX, 4027c20c4267SAnil Ravindranath pinstance->int_regs.host_ioa_interrupt_reg); 4028c20c4267SAnil Ravindranath ioread32(pinstance->int_regs.host_ioa_interrupt_reg); 4029c20c4267SAnil Ravindranath } 4030c20c4267SAnil Ravindranath 4031eab5c150SChristoph Hellwig return 0; 4032c20c4267SAnil Ravindranath 4033eab5c150SChristoph Hellwig out_unwind: 4034eab5c150SChristoph Hellwig while (--i > 0) 4035eab5c150SChristoph Hellwig free_irq(pci_irq_vector(pdev, i), &pinstance->hrrq_vector[i]); 4036eab5c150SChristoph Hellwig pci_free_irq_vectors(pdev); 4037c20c4267SAnil Ravindranath return rc; 403889a36810SAnil Ravindranath } 403989a36810SAnil Ravindranath 404089a36810SAnil Ravindranath /** 404189a36810SAnil Ravindranath * pmcraid_release_cmd_blocks - release buufers allocated for command blocks 404289a36810SAnil Ravindranath * @pinstance: per adapter instance structure pointer 404389a36810SAnil Ravindranath * @max_index: number of buffer blocks to release 404489a36810SAnil Ravindranath * 404589a36810SAnil Ravindranath * Return Value 404689a36810SAnil Ravindranath * None 404789a36810SAnil Ravindranath */ 404889a36810SAnil Ravindranath static void 404989a36810SAnil Ravindranath pmcraid_release_cmd_blocks(struct pmcraid_instance *pinstance, int max_index) 405089a36810SAnil Ravindranath { 405189a36810SAnil Ravindranath int i; 405289a36810SAnil Ravindranath for (i = 0; i < max_index; i++) { 405389a36810SAnil Ravindranath kmem_cache_free(pinstance->cmd_cachep, pinstance->cmd_list[i]); 405489a36810SAnil Ravindranath pinstance->cmd_list[i] = NULL; 405589a36810SAnil Ravindranath } 405689a36810SAnil Ravindranath kmem_cache_destroy(pinstance->cmd_cachep); 405789a36810SAnil Ravindranath pinstance->cmd_cachep = NULL; 405889a36810SAnil Ravindranath } 405989a36810SAnil Ravindranath 406089a36810SAnil Ravindranath /** 406189a36810SAnil Ravindranath * pmcraid_release_control_blocks - releases buffers alloced for control blocks 406289a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 406389a36810SAnil Ravindranath * @max_index: number of buffers (from 0 onwards) to release 406489a36810SAnil Ravindranath * 406589a36810SAnil Ravindranath * This function assumes that the command blocks for which control blocks are 406689a36810SAnil Ravindranath * linked are not released. 406789a36810SAnil Ravindranath * 406889a36810SAnil Ravindranath * Return Value 406989a36810SAnil Ravindranath * None 407089a36810SAnil Ravindranath */ 407189a36810SAnil Ravindranath static void 407289a36810SAnil Ravindranath pmcraid_release_control_blocks( 407389a36810SAnil Ravindranath struct pmcraid_instance *pinstance, 407489a36810SAnil Ravindranath int max_index 407589a36810SAnil Ravindranath ) 407689a36810SAnil Ravindranath { 407789a36810SAnil Ravindranath int i; 407889a36810SAnil Ravindranath 407989a36810SAnil Ravindranath if (pinstance->control_pool == NULL) 408089a36810SAnil Ravindranath return; 408189a36810SAnil Ravindranath 408289a36810SAnil Ravindranath for (i = 0; i < max_index; i++) { 4083a7ec87a9SRomain Perier dma_pool_free(pinstance->control_pool, 408489a36810SAnil Ravindranath pinstance->cmd_list[i]->ioa_cb, 408589a36810SAnil Ravindranath pinstance->cmd_list[i]->ioa_cb_bus_addr); 408689a36810SAnil Ravindranath pinstance->cmd_list[i]->ioa_cb = NULL; 408789a36810SAnil Ravindranath pinstance->cmd_list[i]->ioa_cb_bus_addr = 0; 408889a36810SAnil Ravindranath } 4089a7ec87a9SRomain Perier dma_pool_destroy(pinstance->control_pool); 409089a36810SAnil Ravindranath pinstance->control_pool = NULL; 409189a36810SAnil Ravindranath } 409289a36810SAnil Ravindranath 409389a36810SAnil Ravindranath /** 409489a36810SAnil Ravindranath * pmcraid_allocate_cmd_blocks - allocate memory for cmd block structures 40953673b7b0SLee Jones * @pinstance: pointer to per adapter instance structure 409689a36810SAnil Ravindranath * 409789a36810SAnil Ravindranath * Allocates memory for command blocks using kernel slab allocator. 409889a36810SAnil Ravindranath * 409989a36810SAnil Ravindranath * Return Value 410089a36810SAnil Ravindranath * 0 in case of success; -ENOMEM in case of failure 410189a36810SAnil Ravindranath */ 41026f039790SGreg Kroah-Hartman static int pmcraid_allocate_cmd_blocks(struct pmcraid_instance *pinstance) 410389a36810SAnil Ravindranath { 410489a36810SAnil Ravindranath int i; 410589a36810SAnil Ravindranath 410689a36810SAnil Ravindranath sprintf(pinstance->cmd_pool_name, "pmcraid_cmd_pool_%d", 410789a36810SAnil Ravindranath pinstance->host->unique_id); 410889a36810SAnil Ravindranath 410989a36810SAnil Ravindranath 411089a36810SAnil Ravindranath pinstance->cmd_cachep = kmem_cache_create( 411189a36810SAnil Ravindranath pinstance->cmd_pool_name, 411289a36810SAnil Ravindranath sizeof(struct pmcraid_cmd), 0, 411389a36810SAnil Ravindranath SLAB_HWCACHE_ALIGN, NULL); 411489a36810SAnil Ravindranath if (!pinstance->cmd_cachep) 411589a36810SAnil Ravindranath return -ENOMEM; 411689a36810SAnil Ravindranath 411789a36810SAnil Ravindranath for (i = 0; i < PMCRAID_MAX_CMD; i++) { 411889a36810SAnil Ravindranath pinstance->cmd_list[i] = 411989a36810SAnil Ravindranath kmem_cache_alloc(pinstance->cmd_cachep, GFP_KERNEL); 412089a36810SAnil Ravindranath if (!pinstance->cmd_list[i]) { 412189a36810SAnil Ravindranath pmcraid_release_cmd_blocks(pinstance, i); 412289a36810SAnil Ravindranath return -ENOMEM; 412389a36810SAnil Ravindranath } 412489a36810SAnil Ravindranath } 412589a36810SAnil Ravindranath return 0; 412689a36810SAnil Ravindranath } 412789a36810SAnil Ravindranath 412889a36810SAnil Ravindranath /** 412989a36810SAnil Ravindranath * pmcraid_allocate_control_blocks - allocates memory control blocks 413089a36810SAnil Ravindranath * @pinstance : pointer to per adapter instance structure 413189a36810SAnil Ravindranath * 413289a36810SAnil Ravindranath * This function allocates PCI memory for DMAable buffers like IOARCB, IOADLs 413389a36810SAnil Ravindranath * and IOASAs. This is called after command blocks are already allocated. 413489a36810SAnil Ravindranath * 413589a36810SAnil Ravindranath * Return Value 413689a36810SAnil Ravindranath * 0 in case it can allocate all control blocks, otherwise -ENOMEM 413789a36810SAnil Ravindranath */ 41386f039790SGreg Kroah-Hartman static int pmcraid_allocate_control_blocks(struct pmcraid_instance *pinstance) 413989a36810SAnil Ravindranath { 414089a36810SAnil Ravindranath int i; 414189a36810SAnil Ravindranath 414289a36810SAnil Ravindranath sprintf(pinstance->ctl_pool_name, "pmcraid_control_pool_%d", 414389a36810SAnil Ravindranath pinstance->host->unique_id); 414489a36810SAnil Ravindranath 414589a36810SAnil Ravindranath pinstance->control_pool = 4146a7ec87a9SRomain Perier dma_pool_create(pinstance->ctl_pool_name, 4147a7ec87a9SRomain Perier &pinstance->pdev->dev, 414889a36810SAnil Ravindranath sizeof(struct pmcraid_control_block), 414989a36810SAnil Ravindranath PMCRAID_IOARCB_ALIGNMENT, 0); 415089a36810SAnil Ravindranath 415189a36810SAnil Ravindranath if (!pinstance->control_pool) 415289a36810SAnil Ravindranath return -ENOMEM; 415389a36810SAnil Ravindranath 415489a36810SAnil Ravindranath for (i = 0; i < PMCRAID_MAX_CMD; i++) { 415589a36810SAnil Ravindranath pinstance->cmd_list[i]->ioa_cb = 4156f8f794a1SWu Bo dma_pool_zalloc( 415789a36810SAnil Ravindranath pinstance->control_pool, 415889a36810SAnil Ravindranath GFP_KERNEL, 415989a36810SAnil Ravindranath &(pinstance->cmd_list[i]->ioa_cb_bus_addr)); 416089a36810SAnil Ravindranath 416189a36810SAnil Ravindranath if (!pinstance->cmd_list[i]->ioa_cb) { 416289a36810SAnil Ravindranath pmcraid_release_control_blocks(pinstance, i); 416389a36810SAnil Ravindranath return -ENOMEM; 416489a36810SAnil Ravindranath } 416589a36810SAnil Ravindranath } 416689a36810SAnil Ravindranath return 0; 416789a36810SAnil Ravindranath } 416889a36810SAnil Ravindranath 416989a36810SAnil Ravindranath /** 417089a36810SAnil Ravindranath * pmcraid_release_host_rrqs - release memory allocated for hrrq buffer(s) 417189a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 417289a36810SAnil Ravindranath * @maxindex: size of hrrq buffer pointer array 417389a36810SAnil Ravindranath * 417489a36810SAnil Ravindranath * Return Value 417589a36810SAnil Ravindranath * None 417689a36810SAnil Ravindranath */ 417789a36810SAnil Ravindranath static void 417889a36810SAnil Ravindranath pmcraid_release_host_rrqs(struct pmcraid_instance *pinstance, int maxindex) 417989a36810SAnil Ravindranath { 418089a36810SAnil Ravindranath int i; 418189a36810SAnil Ravindranath 4182371a6c32SChristoph Hellwig for (i = 0; i < maxindex; i++) { 4183371a6c32SChristoph Hellwig dma_free_coherent(&pinstance->pdev->dev, 418489a36810SAnil Ravindranath HRRQ_ENTRY_SIZE * PMCRAID_MAX_CMD, 418589a36810SAnil Ravindranath pinstance->hrrq_start[i], 418689a36810SAnil Ravindranath pinstance->hrrq_start_bus_addr[i]); 418789a36810SAnil Ravindranath 418889a36810SAnil Ravindranath /* reset pointers and toggle bit to zeros */ 418989a36810SAnil Ravindranath pinstance->hrrq_start[i] = NULL; 419089a36810SAnil Ravindranath pinstance->hrrq_start_bus_addr[i] = 0; 419189a36810SAnil Ravindranath pinstance->host_toggle_bit[i] = 0; 419289a36810SAnil Ravindranath } 419389a36810SAnil Ravindranath } 419489a36810SAnil Ravindranath 419589a36810SAnil Ravindranath /** 419689a36810SAnil Ravindranath * pmcraid_allocate_host_rrqs - Allocate and initialize host RRQ buffers 419789a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 419889a36810SAnil Ravindranath * 419989a36810SAnil Ravindranath * Return value 420089a36810SAnil Ravindranath * 0 hrrq buffers are allocated, -ENOMEM otherwise. 420189a36810SAnil Ravindranath */ 42026f039790SGreg Kroah-Hartman static int pmcraid_allocate_host_rrqs(struct pmcraid_instance *pinstance) 420389a36810SAnil Ravindranath { 4204c20c4267SAnil Ravindranath int i, buffer_size; 4205c20c4267SAnil Ravindranath 4206c20c4267SAnil Ravindranath buffer_size = HRRQ_ENTRY_SIZE * PMCRAID_MAX_CMD; 420789a36810SAnil Ravindranath 420889a36810SAnil Ravindranath for (i = 0; i < pinstance->num_hrrq; i++) { 420989a36810SAnil Ravindranath pinstance->hrrq_start[i] = 4210371a6c32SChristoph Hellwig dma_alloc_coherent(&pinstance->pdev->dev, buffer_size, 4211371a6c32SChristoph Hellwig &pinstance->hrrq_start_bus_addr[i], 4212371a6c32SChristoph Hellwig GFP_KERNEL); 4213144b139cSArnd Bergmann if (!pinstance->hrrq_start[i]) { 4214c20c4267SAnil Ravindranath pmcraid_err("pci_alloc failed for hrrq vector : %d\n", 4215c20c4267SAnil Ravindranath i); 421689a36810SAnil Ravindranath pmcraid_release_host_rrqs(pinstance, i); 421789a36810SAnil Ravindranath return -ENOMEM; 421889a36810SAnil Ravindranath } 421989a36810SAnil Ravindranath 422089a36810SAnil Ravindranath pinstance->hrrq_curr[i] = pinstance->hrrq_start[i]; 422189a36810SAnil Ravindranath pinstance->hrrq_end[i] = 4222c20c4267SAnil Ravindranath pinstance->hrrq_start[i] + PMCRAID_MAX_CMD - 1; 422389a36810SAnil Ravindranath pinstance->host_toggle_bit[i] = 1; 422489a36810SAnil Ravindranath spin_lock_init(&pinstance->hrrq_lock[i]); 422589a36810SAnil Ravindranath } 422689a36810SAnil Ravindranath return 0; 422789a36810SAnil Ravindranath } 422889a36810SAnil Ravindranath 422989a36810SAnil Ravindranath /** 423089a36810SAnil Ravindranath * pmcraid_release_hcams - release HCAM buffers 423189a36810SAnil Ravindranath * 423289a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 423389a36810SAnil Ravindranath * 423489a36810SAnil Ravindranath * Return value 423589a36810SAnil Ravindranath * none 423689a36810SAnil Ravindranath */ 423789a36810SAnil Ravindranath static void pmcraid_release_hcams(struct pmcraid_instance *pinstance) 423889a36810SAnil Ravindranath { 423989a36810SAnil Ravindranath if (pinstance->ccn.msg != NULL) { 4240371a6c32SChristoph Hellwig dma_free_coherent(&pinstance->pdev->dev, 424189a36810SAnil Ravindranath PMCRAID_AEN_HDR_SIZE + 4242c20c4267SAnil Ravindranath sizeof(struct pmcraid_hcam_ccn_ext), 424389a36810SAnil Ravindranath pinstance->ccn.msg, 424489a36810SAnil Ravindranath pinstance->ccn.baddr); 424589a36810SAnil Ravindranath 424689a36810SAnil Ravindranath pinstance->ccn.msg = NULL; 424789a36810SAnil Ravindranath pinstance->ccn.hcam = NULL; 424889a36810SAnil Ravindranath pinstance->ccn.baddr = 0; 424989a36810SAnil Ravindranath } 425089a36810SAnil Ravindranath 425189a36810SAnil Ravindranath if (pinstance->ldn.msg != NULL) { 4252371a6c32SChristoph Hellwig dma_free_coherent(&pinstance->pdev->dev, 425389a36810SAnil Ravindranath PMCRAID_AEN_HDR_SIZE + 425489a36810SAnil Ravindranath sizeof(struct pmcraid_hcam_ldn), 425589a36810SAnil Ravindranath pinstance->ldn.msg, 425689a36810SAnil Ravindranath pinstance->ldn.baddr); 425789a36810SAnil Ravindranath 425889a36810SAnil Ravindranath pinstance->ldn.msg = NULL; 425989a36810SAnil Ravindranath pinstance->ldn.hcam = NULL; 426089a36810SAnil Ravindranath pinstance->ldn.baddr = 0; 426189a36810SAnil Ravindranath } 426289a36810SAnil Ravindranath } 426389a36810SAnil Ravindranath 426489a36810SAnil Ravindranath /** 426589a36810SAnil Ravindranath * pmcraid_allocate_hcams - allocates HCAM buffers 426689a36810SAnil Ravindranath * @pinstance : pointer to per adapter instance structure 426789a36810SAnil Ravindranath * 426889a36810SAnil Ravindranath * Return Value: 426989a36810SAnil Ravindranath * 0 in case of successful allocation, non-zero otherwise 427089a36810SAnil Ravindranath */ 427189a36810SAnil Ravindranath static int pmcraid_allocate_hcams(struct pmcraid_instance *pinstance) 427289a36810SAnil Ravindranath { 4273371a6c32SChristoph Hellwig pinstance->ccn.msg = dma_alloc_coherent(&pinstance->pdev->dev, 427489a36810SAnil Ravindranath PMCRAID_AEN_HDR_SIZE + 4275c20c4267SAnil Ravindranath sizeof(struct pmcraid_hcam_ccn_ext), 4276371a6c32SChristoph Hellwig &pinstance->ccn.baddr, GFP_KERNEL); 427789a36810SAnil Ravindranath 4278371a6c32SChristoph Hellwig pinstance->ldn.msg = dma_alloc_coherent(&pinstance->pdev->dev, 427989a36810SAnil Ravindranath PMCRAID_AEN_HDR_SIZE + 428089a36810SAnil Ravindranath sizeof(struct pmcraid_hcam_ldn), 4281371a6c32SChristoph Hellwig &pinstance->ldn.baddr, GFP_KERNEL); 428289a36810SAnil Ravindranath 428389a36810SAnil Ravindranath if (pinstance->ldn.msg == NULL || pinstance->ccn.msg == NULL) { 428489a36810SAnil Ravindranath pmcraid_release_hcams(pinstance); 428589a36810SAnil Ravindranath } else { 428689a36810SAnil Ravindranath pinstance->ccn.hcam = 428789a36810SAnil Ravindranath (void *)pinstance->ccn.msg + PMCRAID_AEN_HDR_SIZE; 428889a36810SAnil Ravindranath pinstance->ldn.hcam = 428989a36810SAnil Ravindranath (void *)pinstance->ldn.msg + PMCRAID_AEN_HDR_SIZE; 429089a36810SAnil Ravindranath 429189a36810SAnil Ravindranath atomic_set(&pinstance->ccn.ignore, 0); 429289a36810SAnil Ravindranath atomic_set(&pinstance->ldn.ignore, 0); 429389a36810SAnil Ravindranath } 429489a36810SAnil Ravindranath 429589a36810SAnil Ravindranath return (pinstance->ldn.msg == NULL) ? -ENOMEM : 0; 429689a36810SAnil Ravindranath } 429789a36810SAnil Ravindranath 429889a36810SAnil Ravindranath /** 429989a36810SAnil Ravindranath * pmcraid_release_config_buffers - release config.table buffers 430089a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 430189a36810SAnil Ravindranath * 430289a36810SAnil Ravindranath * Return Value 430389a36810SAnil Ravindranath * none 430489a36810SAnil Ravindranath */ 430589a36810SAnil Ravindranath static void pmcraid_release_config_buffers(struct pmcraid_instance *pinstance) 430689a36810SAnil Ravindranath { 430789a36810SAnil Ravindranath if (pinstance->cfg_table != NULL && 430889a36810SAnil Ravindranath pinstance->cfg_table_bus_addr != 0) { 4309371a6c32SChristoph Hellwig dma_free_coherent(&pinstance->pdev->dev, 431089a36810SAnil Ravindranath sizeof(struct pmcraid_config_table), 431189a36810SAnil Ravindranath pinstance->cfg_table, 431289a36810SAnil Ravindranath pinstance->cfg_table_bus_addr); 431389a36810SAnil Ravindranath pinstance->cfg_table = NULL; 431489a36810SAnil Ravindranath pinstance->cfg_table_bus_addr = 0; 431589a36810SAnil Ravindranath } 431689a36810SAnil Ravindranath 431789a36810SAnil Ravindranath if (pinstance->res_entries != NULL) { 431889a36810SAnil Ravindranath int i; 431989a36810SAnil Ravindranath 432089a36810SAnil Ravindranath for (i = 0; i < PMCRAID_MAX_RESOURCES; i++) 432189a36810SAnil Ravindranath list_del(&pinstance->res_entries[i].queue); 432289a36810SAnil Ravindranath kfree(pinstance->res_entries); 432389a36810SAnil Ravindranath pinstance->res_entries = NULL; 432489a36810SAnil Ravindranath } 432589a36810SAnil Ravindranath 432689a36810SAnil Ravindranath pmcraid_release_hcams(pinstance); 432789a36810SAnil Ravindranath } 432889a36810SAnil Ravindranath 432989a36810SAnil Ravindranath /** 433089a36810SAnil Ravindranath * pmcraid_allocate_config_buffers - allocates DMAable memory for config table 433189a36810SAnil Ravindranath * @pinstance : pointer to per adapter instance structure 433289a36810SAnil Ravindranath * 433389a36810SAnil Ravindranath * Return Value 433489a36810SAnil Ravindranath * 0 for successful allocation, -ENOMEM for any failure 433589a36810SAnil Ravindranath */ 43366f039790SGreg Kroah-Hartman static int pmcraid_allocate_config_buffers(struct pmcraid_instance *pinstance) 433789a36810SAnil Ravindranath { 433889a36810SAnil Ravindranath int i; 433989a36810SAnil Ravindranath 434089a36810SAnil Ravindranath pinstance->res_entries = 43416396bb22SKees Cook kcalloc(PMCRAID_MAX_RESOURCES, 43426396bb22SKees Cook sizeof(struct pmcraid_resource_entry), 43436396bb22SKees Cook GFP_KERNEL); 434489a36810SAnil Ravindranath 434589a36810SAnil Ravindranath if (NULL == pinstance->res_entries) { 434689a36810SAnil Ravindranath pmcraid_err("failed to allocate memory for resource table\n"); 434789a36810SAnil Ravindranath return -ENOMEM; 434889a36810SAnil Ravindranath } 434989a36810SAnil Ravindranath 435089a36810SAnil Ravindranath for (i = 0; i < PMCRAID_MAX_RESOURCES; i++) 435189a36810SAnil Ravindranath list_add_tail(&pinstance->res_entries[i].queue, 435289a36810SAnil Ravindranath &pinstance->free_res_q); 435389a36810SAnil Ravindranath 4354371a6c32SChristoph Hellwig pinstance->cfg_table = dma_alloc_coherent(&pinstance->pdev->dev, 435589a36810SAnil Ravindranath sizeof(struct pmcraid_config_table), 4356371a6c32SChristoph Hellwig &pinstance->cfg_table_bus_addr, 4357371a6c32SChristoph Hellwig GFP_KERNEL); 435889a36810SAnil Ravindranath 435989a36810SAnil Ravindranath if (NULL == pinstance->cfg_table) { 436089a36810SAnil Ravindranath pmcraid_err("couldn't alloc DMA memory for config table\n"); 436189a36810SAnil Ravindranath pmcraid_release_config_buffers(pinstance); 436289a36810SAnil Ravindranath return -ENOMEM; 436389a36810SAnil Ravindranath } 436489a36810SAnil Ravindranath 436589a36810SAnil Ravindranath if (pmcraid_allocate_hcams(pinstance)) { 436689a36810SAnil Ravindranath pmcraid_err("could not alloc DMA memory for HCAMS\n"); 436789a36810SAnil Ravindranath pmcraid_release_config_buffers(pinstance); 436889a36810SAnil Ravindranath return -ENOMEM; 436989a36810SAnil Ravindranath } 437089a36810SAnil Ravindranath 437189a36810SAnil Ravindranath return 0; 437289a36810SAnil Ravindranath } 437389a36810SAnil Ravindranath 437489a36810SAnil Ravindranath /** 437589a36810SAnil Ravindranath * pmcraid_init_tasklets - registers tasklets for response handling 437689a36810SAnil Ravindranath * 437789a36810SAnil Ravindranath * @pinstance: pointer adapter instance structure 437889a36810SAnil Ravindranath * 437989a36810SAnil Ravindranath * Return value 438089a36810SAnil Ravindranath * none 438189a36810SAnil Ravindranath */ 438289a36810SAnil Ravindranath static void pmcraid_init_tasklets(struct pmcraid_instance *pinstance) 438389a36810SAnil Ravindranath { 438489a36810SAnil Ravindranath int i; 438589a36810SAnil Ravindranath for (i = 0; i < pinstance->num_hrrq; i++) 438689a36810SAnil Ravindranath tasklet_init(&pinstance->isr_tasklet[i], 438789a36810SAnil Ravindranath pmcraid_tasklet_function, 438889a36810SAnil Ravindranath (unsigned long)&pinstance->hrrq_vector[i]); 438989a36810SAnil Ravindranath } 439089a36810SAnil Ravindranath 439189a36810SAnil Ravindranath /** 439289a36810SAnil Ravindranath * pmcraid_kill_tasklets - destroys tasklets registered for response handling 439389a36810SAnil Ravindranath * 439489a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 439589a36810SAnil Ravindranath * 439689a36810SAnil Ravindranath * Return value 439789a36810SAnil Ravindranath * none 439889a36810SAnil Ravindranath */ 439989a36810SAnil Ravindranath static void pmcraid_kill_tasklets(struct pmcraid_instance *pinstance) 440089a36810SAnil Ravindranath { 440189a36810SAnil Ravindranath int i; 440289a36810SAnil Ravindranath for (i = 0; i < pinstance->num_hrrq; i++) 440389a36810SAnil Ravindranath tasklet_kill(&pinstance->isr_tasklet[i]); 440489a36810SAnil Ravindranath } 440589a36810SAnil Ravindranath 440689a36810SAnil Ravindranath /** 4407c20c4267SAnil Ravindranath * pmcraid_release_buffers - release per-adapter buffers allocated 4408c20c4267SAnil Ravindranath * 4409c20c4267SAnil Ravindranath * @pinstance: pointer to adapter soft state 4410c20c4267SAnil Ravindranath * 4411c20c4267SAnil Ravindranath * Return Value 4412c20c4267SAnil Ravindranath * none 4413c20c4267SAnil Ravindranath */ 4414c20c4267SAnil Ravindranath static void pmcraid_release_buffers(struct pmcraid_instance *pinstance) 4415c20c4267SAnil Ravindranath { 4416c20c4267SAnil Ravindranath pmcraid_release_config_buffers(pinstance); 4417c20c4267SAnil Ravindranath pmcraid_release_control_blocks(pinstance, PMCRAID_MAX_CMD); 4418c20c4267SAnil Ravindranath pmcraid_release_cmd_blocks(pinstance, PMCRAID_MAX_CMD); 4419c20c4267SAnil Ravindranath pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); 4420c20c4267SAnil Ravindranath 4421c20c4267SAnil Ravindranath if (pinstance->inq_data != NULL) { 4422371a6c32SChristoph Hellwig dma_free_coherent(&pinstance->pdev->dev, 4423c20c4267SAnil Ravindranath sizeof(struct pmcraid_inquiry_data), 4424c20c4267SAnil Ravindranath pinstance->inq_data, 4425c20c4267SAnil Ravindranath pinstance->inq_data_baddr); 4426c20c4267SAnil Ravindranath 4427c20c4267SAnil Ravindranath pinstance->inq_data = NULL; 4428c20c4267SAnil Ravindranath pinstance->inq_data_baddr = 0; 4429c20c4267SAnil Ravindranath } 4430592488a3SAnil Ravindranath 4431592488a3SAnil Ravindranath if (pinstance->timestamp_data != NULL) { 4432371a6c32SChristoph Hellwig dma_free_coherent(&pinstance->pdev->dev, 4433592488a3SAnil Ravindranath sizeof(struct pmcraid_timestamp_data), 4434592488a3SAnil Ravindranath pinstance->timestamp_data, 4435592488a3SAnil Ravindranath pinstance->timestamp_data_baddr); 4436592488a3SAnil Ravindranath 4437592488a3SAnil Ravindranath pinstance->timestamp_data = NULL; 4438592488a3SAnil Ravindranath pinstance->timestamp_data_baddr = 0; 4439592488a3SAnil Ravindranath } 4440c20c4267SAnil Ravindranath } 4441c20c4267SAnil Ravindranath 4442c20c4267SAnil Ravindranath /** 444389a36810SAnil Ravindranath * pmcraid_init_buffers - allocates memory and initializes various structures 444489a36810SAnil Ravindranath * @pinstance: pointer to per adapter instance structure 444589a36810SAnil Ravindranath * 444689a36810SAnil Ravindranath * This routine pre-allocates memory based on the type of block as below: 444789a36810SAnil Ravindranath * cmdblocks(PMCRAID_MAX_CMD): kernel memory using kernel's slab_allocator, 444889a36810SAnil Ravindranath * IOARCBs(PMCRAID_MAX_CMD) : DMAable memory, using pci pool allocator 4449371a6c32SChristoph Hellwig * config-table entries : DMAable memory using dma_alloc_coherent 4450371a6c32SChristoph Hellwig * HostRRQs : DMAable memory, using dma_alloc_coherent 445189a36810SAnil Ravindranath * 445289a36810SAnil Ravindranath * Return Value 445389a36810SAnil Ravindranath * 0 in case all of the blocks are allocated, -ENOMEM otherwise. 445489a36810SAnil Ravindranath */ 44556f039790SGreg Kroah-Hartman static int pmcraid_init_buffers(struct pmcraid_instance *pinstance) 445689a36810SAnil Ravindranath { 445789a36810SAnil Ravindranath int i; 445889a36810SAnil Ravindranath 445989a36810SAnil Ravindranath if (pmcraid_allocate_host_rrqs(pinstance)) { 446089a36810SAnil Ravindranath pmcraid_err("couldn't allocate memory for %d host rrqs\n", 446189a36810SAnil Ravindranath pinstance->num_hrrq); 446289a36810SAnil Ravindranath return -ENOMEM; 446389a36810SAnil Ravindranath } 446489a36810SAnil Ravindranath 446589a36810SAnil Ravindranath if (pmcraid_allocate_config_buffers(pinstance)) { 446689a36810SAnil Ravindranath pmcraid_err("couldn't allocate memory for config buffers\n"); 446789a36810SAnil Ravindranath pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); 446889a36810SAnil Ravindranath return -ENOMEM; 446989a36810SAnil Ravindranath } 447089a36810SAnil Ravindranath 447189a36810SAnil Ravindranath if (pmcraid_allocate_cmd_blocks(pinstance)) { 447289a36810SAnil Ravindranath pmcraid_err("couldn't allocate memory for cmd blocks\n"); 447389a36810SAnil Ravindranath pmcraid_release_config_buffers(pinstance); 447489a36810SAnil Ravindranath pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); 447589a36810SAnil Ravindranath return -ENOMEM; 447689a36810SAnil Ravindranath } 447789a36810SAnil Ravindranath 447889a36810SAnil Ravindranath if (pmcraid_allocate_control_blocks(pinstance)) { 447989a36810SAnil Ravindranath pmcraid_err("couldn't allocate memory control blocks\n"); 448089a36810SAnil Ravindranath pmcraid_release_config_buffers(pinstance); 448189a36810SAnil Ravindranath pmcraid_release_cmd_blocks(pinstance, PMCRAID_MAX_CMD); 448289a36810SAnil Ravindranath pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); 448389a36810SAnil Ravindranath return -ENOMEM; 448489a36810SAnil Ravindranath } 448589a36810SAnil Ravindranath 4486c20c4267SAnil Ravindranath /* allocate DMAable memory for page D0 INQUIRY buffer */ 4487371a6c32SChristoph Hellwig pinstance->inq_data = dma_alloc_coherent(&pinstance->pdev->dev, 4488c20c4267SAnil Ravindranath sizeof(struct pmcraid_inquiry_data), 4489371a6c32SChristoph Hellwig &pinstance->inq_data_baddr, GFP_KERNEL); 4490c20c4267SAnil Ravindranath if (pinstance->inq_data == NULL) { 4491c20c4267SAnil Ravindranath pmcraid_err("couldn't allocate DMA memory for INQUIRY\n"); 4492c20c4267SAnil Ravindranath pmcraid_release_buffers(pinstance); 4493c20c4267SAnil Ravindranath return -ENOMEM; 4494c20c4267SAnil Ravindranath } 4495c20c4267SAnil Ravindranath 4496592488a3SAnil Ravindranath /* allocate DMAable memory for set timestamp data buffer */ 4497371a6c32SChristoph Hellwig pinstance->timestamp_data = dma_alloc_coherent(&pinstance->pdev->dev, 4498592488a3SAnil Ravindranath sizeof(struct pmcraid_timestamp_data), 4499371a6c32SChristoph Hellwig &pinstance->timestamp_data_baddr, 4500371a6c32SChristoph Hellwig GFP_KERNEL); 4501592488a3SAnil Ravindranath if (pinstance->timestamp_data == NULL) { 4502592488a3SAnil Ravindranath pmcraid_err("couldn't allocate DMA memory for \ 4503592488a3SAnil Ravindranath set time_stamp \n"); 4504592488a3SAnil Ravindranath pmcraid_release_buffers(pinstance); 4505592488a3SAnil Ravindranath return -ENOMEM; 4506592488a3SAnil Ravindranath } 4507592488a3SAnil Ravindranath 4508592488a3SAnil Ravindranath 450989a36810SAnil Ravindranath /* Initialize all the command blocks and add them to free pool. No 451089a36810SAnil Ravindranath * need to lock (free_pool_lock) as this is done in initialization 451189a36810SAnil Ravindranath * itself 451289a36810SAnil Ravindranath */ 451389a36810SAnil Ravindranath for (i = 0; i < PMCRAID_MAX_CMD; i++) { 451489a36810SAnil Ravindranath struct pmcraid_cmd *cmdp = pinstance->cmd_list[i]; 451589a36810SAnil Ravindranath pmcraid_init_cmdblk(cmdp, i); 451689a36810SAnil Ravindranath cmdp->drv_inst = pinstance; 451789a36810SAnil Ravindranath list_add_tail(&cmdp->free_list, &pinstance->free_cmd_pool); 451889a36810SAnil Ravindranath } 451989a36810SAnil Ravindranath 452089a36810SAnil Ravindranath return 0; 452189a36810SAnil Ravindranath } 452289a36810SAnil Ravindranath 452389a36810SAnil Ravindranath /** 452489a36810SAnil Ravindranath * pmcraid_reinit_buffers - resets various buffer pointers 452589a36810SAnil Ravindranath * @pinstance: pointer to adapter instance 452689a36810SAnil Ravindranath * Return value 452789a36810SAnil Ravindranath * none 452889a36810SAnil Ravindranath */ 452989a36810SAnil Ravindranath static void pmcraid_reinit_buffers(struct pmcraid_instance *pinstance) 453089a36810SAnil Ravindranath { 453189a36810SAnil Ravindranath int i; 453289a36810SAnil Ravindranath int buffer_size = HRRQ_ENTRY_SIZE * PMCRAID_MAX_CMD; 453389a36810SAnil Ravindranath 453489a36810SAnil Ravindranath for (i = 0; i < pinstance->num_hrrq; i++) { 453589a36810SAnil Ravindranath memset(pinstance->hrrq_start[i], 0, buffer_size); 453689a36810SAnil Ravindranath pinstance->hrrq_curr[i] = pinstance->hrrq_start[i]; 453789a36810SAnil Ravindranath pinstance->hrrq_end[i] = 453889a36810SAnil Ravindranath pinstance->hrrq_start[i] + PMCRAID_MAX_CMD - 1; 453989a36810SAnil Ravindranath pinstance->host_toggle_bit[i] = 1; 454089a36810SAnil Ravindranath } 454189a36810SAnil Ravindranath } 454289a36810SAnil Ravindranath 454389a36810SAnil Ravindranath /** 454489a36810SAnil Ravindranath * pmcraid_init_instance - initialize per instance data structure 454589a36810SAnil Ravindranath * @pdev: pointer to pci device structure 454689a36810SAnil Ravindranath * @host: pointer to Scsi_Host structure 454789a36810SAnil Ravindranath * @mapped_pci_addr: memory mapped IOA configuration registers 454889a36810SAnil Ravindranath * 454989a36810SAnil Ravindranath * Return Value 455089a36810SAnil Ravindranath * 0 on success, non-zero in case of any failure 455189a36810SAnil Ravindranath */ 45526f039790SGreg Kroah-Hartman static int pmcraid_init_instance(struct pci_dev *pdev, struct Scsi_Host *host, 45536f039790SGreg Kroah-Hartman void __iomem *mapped_pci_addr) 455489a36810SAnil Ravindranath { 455589a36810SAnil Ravindranath struct pmcraid_instance *pinstance = 455689a36810SAnil Ravindranath (struct pmcraid_instance *)host->hostdata; 455789a36810SAnil Ravindranath 455889a36810SAnil Ravindranath pinstance->host = host; 455989a36810SAnil Ravindranath pinstance->pdev = pdev; 456089a36810SAnil Ravindranath 456189a36810SAnil Ravindranath /* Initialize register addresses */ 456289a36810SAnil Ravindranath pinstance->mapped_dma_addr = mapped_pci_addr; 456389a36810SAnil Ravindranath 456489a36810SAnil Ravindranath /* Initialize chip-specific details */ 456589a36810SAnil Ravindranath { 456689a36810SAnil Ravindranath struct pmcraid_chip_details *chip_cfg = pinstance->chip_cfg; 456789a36810SAnil Ravindranath struct pmcraid_interrupts *pint_regs = &pinstance->int_regs; 456889a36810SAnil Ravindranath 456989a36810SAnil Ravindranath pinstance->ioarrin = mapped_pci_addr + chip_cfg->ioarrin; 457089a36810SAnil Ravindranath 457189a36810SAnil Ravindranath pint_regs->ioa_host_interrupt_reg = 457289a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->ioa_host_intr; 457389a36810SAnil Ravindranath pint_regs->ioa_host_interrupt_clr_reg = 457489a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->ioa_host_intr_clr; 4575c20c4267SAnil Ravindranath pint_regs->ioa_host_msix_interrupt_reg = 4576c20c4267SAnil Ravindranath mapped_pci_addr + chip_cfg->ioa_host_msix_intr; 457789a36810SAnil Ravindranath pint_regs->host_ioa_interrupt_reg = 457889a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->host_ioa_intr; 457989a36810SAnil Ravindranath pint_regs->host_ioa_interrupt_clr_reg = 458089a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->host_ioa_intr_clr; 458189a36810SAnil Ravindranath 458289a36810SAnil Ravindranath /* Current version of firmware exposes interrupt mask set 458389a36810SAnil Ravindranath * and mask clr registers through memory mapped bar0. 458489a36810SAnil Ravindranath */ 458589a36810SAnil Ravindranath pinstance->mailbox = mapped_pci_addr + chip_cfg->mailbox; 458689a36810SAnil Ravindranath pinstance->ioa_status = mapped_pci_addr + chip_cfg->ioastatus; 458789a36810SAnil Ravindranath pint_regs->ioa_host_interrupt_mask_reg = 458889a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->ioa_host_mask; 458989a36810SAnil Ravindranath pint_regs->ioa_host_interrupt_mask_clr_reg = 459089a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->ioa_host_mask_clr; 459189a36810SAnil Ravindranath pint_regs->global_interrupt_mask_reg = 459289a36810SAnil Ravindranath mapped_pci_addr + chip_cfg->global_intr_mask; 4593*21a023ceSJiapeng Chong } 459489a36810SAnil Ravindranath 459589a36810SAnil Ravindranath pinstance->ioa_reset_attempts = 0; 459689a36810SAnil Ravindranath init_waitqueue_head(&pinstance->reset_wait_q); 459789a36810SAnil Ravindranath 459889a36810SAnil Ravindranath atomic_set(&pinstance->outstanding_cmds, 0); 4599c20c4267SAnil Ravindranath atomic_set(&pinstance->last_message_id, 0); 460089a36810SAnil Ravindranath atomic_set(&pinstance->expose_resources, 0); 460189a36810SAnil Ravindranath 460289a36810SAnil Ravindranath INIT_LIST_HEAD(&pinstance->free_res_q); 460389a36810SAnil Ravindranath INIT_LIST_HEAD(&pinstance->used_res_q); 460489a36810SAnil Ravindranath INIT_LIST_HEAD(&pinstance->free_cmd_pool); 460589a36810SAnil Ravindranath INIT_LIST_HEAD(&pinstance->pending_cmd_pool); 460689a36810SAnil Ravindranath 460789a36810SAnil Ravindranath spin_lock_init(&pinstance->free_pool_lock); 460889a36810SAnil Ravindranath spin_lock_init(&pinstance->pending_pool_lock); 460989a36810SAnil Ravindranath spin_lock_init(&pinstance->resource_lock); 461089a36810SAnil Ravindranath mutex_init(&pinstance->aen_queue_lock); 461189a36810SAnil Ravindranath 461289a36810SAnil Ravindranath /* Work-queue (Shared) for deferred processing error handling */ 461389a36810SAnil Ravindranath INIT_WORK(&pinstance->worker_q, pmcraid_worker_function); 461489a36810SAnil Ravindranath 461589a36810SAnil Ravindranath /* Initialize the default log_level */ 461689a36810SAnil Ravindranath pinstance->current_log_level = pmcraid_log_level; 461789a36810SAnil Ravindranath 461889a36810SAnil Ravindranath /* Setup variables required for reset engine */ 461989a36810SAnil Ravindranath pinstance->ioa_state = IOA_STATE_UNKNOWN; 462089a36810SAnil Ravindranath pinstance->reset_cmd = NULL; 462189a36810SAnil Ravindranath return 0; 462289a36810SAnil Ravindranath } 462389a36810SAnil Ravindranath 462489a36810SAnil Ravindranath /** 462589a36810SAnil Ravindranath * pmcraid_shutdown - shutdown adapter controller. 462689a36810SAnil Ravindranath * @pdev: pci device struct 462789a36810SAnil Ravindranath * 462889a36810SAnil Ravindranath * Issues an adapter shutdown to the card waits for its completion 462989a36810SAnil Ravindranath * 463089a36810SAnil Ravindranath * Return value 463189a36810SAnil Ravindranath * none 463289a36810SAnil Ravindranath */ 463389a36810SAnil Ravindranath static void pmcraid_shutdown(struct pci_dev *pdev) 463489a36810SAnil Ravindranath { 463589a36810SAnil Ravindranath struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); 463689a36810SAnil Ravindranath pmcraid_reset_bringdown(pinstance); 463789a36810SAnil Ravindranath } 463889a36810SAnil Ravindranath 463989a36810SAnil Ravindranath 46403673b7b0SLee Jones /* 464189a36810SAnil Ravindranath * pmcraid_get_minor - returns unused minor number from minor number bitmap 464289a36810SAnil Ravindranath */ 464389a36810SAnil Ravindranath static unsigned short pmcraid_get_minor(void) 464489a36810SAnil Ravindranath { 464589a36810SAnil Ravindranath int minor; 464689a36810SAnil Ravindranath 464736d9e0e8SNiklas Cassel minor = find_first_zero_bit(pmcraid_minor, PMCRAID_MAX_ADAPTERS); 464889a36810SAnil Ravindranath __set_bit(minor, pmcraid_minor); 464989a36810SAnil Ravindranath return minor; 465089a36810SAnil Ravindranath } 465189a36810SAnil Ravindranath 46523673b7b0SLee Jones /* 465389a36810SAnil Ravindranath * pmcraid_release_minor - releases given minor back to minor number bitmap 465489a36810SAnil Ravindranath */ 465589a36810SAnil Ravindranath static void pmcraid_release_minor(unsigned short minor) 465689a36810SAnil Ravindranath { 465789a36810SAnil Ravindranath __clear_bit(minor, pmcraid_minor); 465889a36810SAnil Ravindranath } 465989a36810SAnil Ravindranath 466089a36810SAnil Ravindranath /** 466189a36810SAnil Ravindranath * pmcraid_setup_chrdev - allocates a minor number and registers a char device 466289a36810SAnil Ravindranath * 466389a36810SAnil Ravindranath * @pinstance: pointer to adapter instance for which to register device 466489a36810SAnil Ravindranath * 466589a36810SAnil Ravindranath * Return value 466689a36810SAnil Ravindranath * 0 in case of success, otherwise non-zero 466789a36810SAnil Ravindranath */ 466889a36810SAnil Ravindranath static int pmcraid_setup_chrdev(struct pmcraid_instance *pinstance) 466989a36810SAnil Ravindranath { 467089a36810SAnil Ravindranath int minor; 467189a36810SAnil Ravindranath int error; 467289a36810SAnil Ravindranath 467389a36810SAnil Ravindranath minor = pmcraid_get_minor(); 467489a36810SAnil Ravindranath cdev_init(&pinstance->cdev, &pmcraid_fops); 467589a36810SAnil Ravindranath pinstance->cdev.owner = THIS_MODULE; 467689a36810SAnil Ravindranath 467789a36810SAnil Ravindranath error = cdev_add(&pinstance->cdev, MKDEV(pmcraid_major, minor), 1); 467889a36810SAnil Ravindranath 467989a36810SAnil Ravindranath if (error) 468089a36810SAnil Ravindranath pmcraid_release_minor(minor); 468189a36810SAnil Ravindranath else 468289a36810SAnil Ravindranath device_create(pmcraid_class, NULL, MKDEV(pmcraid_major, minor), 4683c20c4267SAnil Ravindranath NULL, "%s%u", PMCRAID_DEVFILE, minor); 468489a36810SAnil Ravindranath return error; 468589a36810SAnil Ravindranath } 468689a36810SAnil Ravindranath 468789a36810SAnil Ravindranath /** 468889a36810SAnil Ravindranath * pmcraid_release_chrdev - unregisters per-adapter management interface 468989a36810SAnil Ravindranath * 469089a36810SAnil Ravindranath * @pinstance: pointer to adapter instance structure 469189a36810SAnil Ravindranath * 469289a36810SAnil Ravindranath * Return value 469389a36810SAnil Ravindranath * none 469489a36810SAnil Ravindranath */ 469589a36810SAnil Ravindranath static void pmcraid_release_chrdev(struct pmcraid_instance *pinstance) 469689a36810SAnil Ravindranath { 469789a36810SAnil Ravindranath pmcraid_release_minor(MINOR(pinstance->cdev.dev)); 469889a36810SAnil Ravindranath device_destroy(pmcraid_class, 469989a36810SAnil Ravindranath MKDEV(pmcraid_major, MINOR(pinstance->cdev.dev))); 470089a36810SAnil Ravindranath cdev_del(&pinstance->cdev); 470189a36810SAnil Ravindranath } 470289a36810SAnil Ravindranath 470389a36810SAnil Ravindranath /** 470489a36810SAnil Ravindranath * pmcraid_remove - IOA hot plug remove entry point 470589a36810SAnil Ravindranath * @pdev: pci device struct 470689a36810SAnil Ravindranath * 470789a36810SAnil Ravindranath * Return value 470889a36810SAnil Ravindranath * none 470989a36810SAnil Ravindranath */ 47106f039790SGreg Kroah-Hartman static void pmcraid_remove(struct pci_dev *pdev) 471189a36810SAnil Ravindranath { 471289a36810SAnil Ravindranath struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); 471389a36810SAnil Ravindranath 471489a36810SAnil Ravindranath /* remove the management interface (/dev file) for this device */ 471589a36810SAnil Ravindranath pmcraid_release_chrdev(pinstance); 471689a36810SAnil Ravindranath 471789a36810SAnil Ravindranath /* remove host template from scsi midlayer */ 471889a36810SAnil Ravindranath scsi_remove_host(pinstance->host); 471989a36810SAnil Ravindranath 472089a36810SAnil Ravindranath /* block requests from mid-layer */ 472189a36810SAnil Ravindranath scsi_block_requests(pinstance->host); 472289a36810SAnil Ravindranath 472389a36810SAnil Ravindranath /* initiate shutdown adapter */ 472489a36810SAnil Ravindranath pmcraid_shutdown(pdev); 472589a36810SAnil Ravindranath 472689a36810SAnil Ravindranath pmcraid_disable_interrupts(pinstance, ~0); 472743829731STejun Heo flush_work(&pinstance->worker_q); 472889a36810SAnil Ravindranath 472989a36810SAnil Ravindranath pmcraid_kill_tasklets(pinstance); 473089a36810SAnil Ravindranath pmcraid_unregister_interrupt_handler(pinstance); 473189a36810SAnil Ravindranath pmcraid_release_buffers(pinstance); 473289a36810SAnil Ravindranath iounmap(pinstance->mapped_dma_addr); 473389a36810SAnil Ravindranath pci_release_regions(pdev); 473489a36810SAnil Ravindranath scsi_host_put(pinstance->host); 473589a36810SAnil Ravindranath pci_disable_device(pdev); 473689a36810SAnil Ravindranath 473789a36810SAnil Ravindranath return; 473889a36810SAnil Ravindranath } 473989a36810SAnil Ravindranath 474089a36810SAnil Ravindranath /** 474189a36810SAnil Ravindranath * pmcraid_suspend - driver suspend entry point for power management 4742ac85cca3SVaibhav Gupta * @dev: Device structure 474389a36810SAnil Ravindranath * 474489a36810SAnil Ravindranath * Return Value - 0 always 474589a36810SAnil Ravindranath */ 4746ac85cca3SVaibhav Gupta static int __maybe_unused pmcraid_suspend(struct device *dev) 474789a36810SAnil Ravindranath { 4748ac85cca3SVaibhav Gupta struct pci_dev *pdev = to_pci_dev(dev); 474989a36810SAnil Ravindranath struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); 475089a36810SAnil Ravindranath 475189a36810SAnil Ravindranath pmcraid_shutdown(pdev); 475289a36810SAnil Ravindranath pmcraid_disable_interrupts(pinstance, ~0); 475389a36810SAnil Ravindranath pmcraid_kill_tasklets(pinstance); 475489a36810SAnil Ravindranath pmcraid_unregister_interrupt_handler(pinstance); 475589a36810SAnil Ravindranath 475689a36810SAnil Ravindranath return 0; 475789a36810SAnil Ravindranath } 475889a36810SAnil Ravindranath 475989a36810SAnil Ravindranath /** 476089a36810SAnil Ravindranath * pmcraid_resume - driver resume entry point PCI power management 4761ac85cca3SVaibhav Gupta * @dev: Device structure 476289a36810SAnil Ravindranath * 476389a36810SAnil Ravindranath * Return Value - 0 in case of success. Error code in case of any failure 476489a36810SAnil Ravindranath */ 4765ac85cca3SVaibhav Gupta static int __maybe_unused pmcraid_resume(struct device *dev) 476689a36810SAnil Ravindranath { 4767ac85cca3SVaibhav Gupta struct pci_dev *pdev = to_pci_dev(dev); 476889a36810SAnil Ravindranath struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); 476989a36810SAnil Ravindranath struct Scsi_Host *host = pinstance->host; 4770ac85cca3SVaibhav Gupta int rc = 0; 477189a36810SAnil Ravindranath 4772371a6c32SChristoph Hellwig if (sizeof(dma_addr_t) == 4 || 4773371a6c32SChristoph Hellwig dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) 4774371a6c32SChristoph Hellwig rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); 477589a36810SAnil Ravindranath 477689a36810SAnil Ravindranath if (rc == 0) 4777371a6c32SChristoph Hellwig rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); 477889a36810SAnil Ravindranath 477989a36810SAnil Ravindranath if (rc != 0) { 478034876402SAnil Ravindranath dev_err(&pdev->dev, "resume: Failed to set PCI DMA mask\n"); 478189a36810SAnil Ravindranath goto disable_device; 478289a36810SAnil Ravindranath } 478389a36810SAnil Ravindranath 4784c20c4267SAnil Ravindranath pmcraid_disable_interrupts(pinstance, ~0); 478589a36810SAnil Ravindranath atomic_set(&pinstance->outstanding_cmds, 0); 478689a36810SAnil Ravindranath rc = pmcraid_register_interrupt_handler(pinstance); 478789a36810SAnil Ravindranath 478889a36810SAnil Ravindranath if (rc) { 478934876402SAnil Ravindranath dev_err(&pdev->dev, 479034876402SAnil Ravindranath "resume: couldn't register interrupt handlers\n"); 479189a36810SAnil Ravindranath rc = -ENODEV; 479289a36810SAnil Ravindranath goto release_host; 479389a36810SAnil Ravindranath } 479489a36810SAnil Ravindranath 479589a36810SAnil Ravindranath pmcraid_init_tasklets(pinstance); 479689a36810SAnil Ravindranath pmcraid_enable_interrupts(pinstance, PMCRAID_PCI_INTERRUPTS); 479789a36810SAnil Ravindranath 479889a36810SAnil Ravindranath /* Start with hard reset sequence which brings up IOA to operational 479989a36810SAnil Ravindranath * state as well as completes the reset sequence. 480089a36810SAnil Ravindranath */ 480189a36810SAnil Ravindranath pinstance->ioa_hard_reset = 1; 480289a36810SAnil Ravindranath 480389a36810SAnil Ravindranath /* Start IOA firmware initialization and bring card to Operational 480489a36810SAnil Ravindranath * state. 480589a36810SAnil Ravindranath */ 480689a36810SAnil Ravindranath if (pmcraid_reset_bringup(pinstance)) { 480734876402SAnil Ravindranath dev_err(&pdev->dev, "couldn't initialize IOA\n"); 480889a36810SAnil Ravindranath rc = -ENODEV; 480989a36810SAnil Ravindranath goto release_tasklets; 481089a36810SAnil Ravindranath } 481189a36810SAnil Ravindranath 481289a36810SAnil Ravindranath return 0; 481389a36810SAnil Ravindranath 481489a36810SAnil Ravindranath release_tasklets: 4815c20c4267SAnil Ravindranath pmcraid_disable_interrupts(pinstance, ~0); 481689a36810SAnil Ravindranath pmcraid_kill_tasklets(pinstance); 481789a36810SAnil Ravindranath pmcraid_unregister_interrupt_handler(pinstance); 481889a36810SAnil Ravindranath 481989a36810SAnil Ravindranath release_host: 482089a36810SAnil Ravindranath scsi_host_put(host); 482189a36810SAnil Ravindranath 482289a36810SAnil Ravindranath disable_device: 482389a36810SAnil Ravindranath 482489a36810SAnil Ravindranath return rc; 482589a36810SAnil Ravindranath } 482689a36810SAnil Ravindranath 482789a36810SAnil Ravindranath /** 482889a36810SAnil Ravindranath * pmcraid_complete_ioa_reset - Called by either timer or tasklet during 482989a36810SAnil Ravindranath * completion of the ioa reset 483089a36810SAnil Ravindranath * @cmd: pointer to reset command block 483189a36810SAnil Ravindranath */ 483289a36810SAnil Ravindranath static void pmcraid_complete_ioa_reset(struct pmcraid_cmd *cmd) 483389a36810SAnil Ravindranath { 483489a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 483589a36810SAnil Ravindranath unsigned long flags; 483689a36810SAnil Ravindranath 483789a36810SAnil Ravindranath spin_lock_irqsave(pinstance->host->host_lock, flags); 483889a36810SAnil Ravindranath pmcraid_ioa_reset(cmd); 483989a36810SAnil Ravindranath spin_unlock_irqrestore(pinstance->host->host_lock, flags); 484089a36810SAnil Ravindranath scsi_unblock_requests(pinstance->host); 484189a36810SAnil Ravindranath schedule_work(&pinstance->worker_q); 484289a36810SAnil Ravindranath } 484389a36810SAnil Ravindranath 484489a36810SAnil Ravindranath /** 484589a36810SAnil Ravindranath * pmcraid_set_supported_devs - sends SET SUPPORTED DEVICES to IOAFP 484689a36810SAnil Ravindranath * 484789a36810SAnil Ravindranath * @cmd: pointer to pmcraid_cmd structure 484889a36810SAnil Ravindranath * 484989a36810SAnil Ravindranath * Return Value 485089a36810SAnil Ravindranath * 0 for success or non-zero for failure cases 485189a36810SAnil Ravindranath */ 485289a36810SAnil Ravindranath static void pmcraid_set_supported_devs(struct pmcraid_cmd *cmd) 485389a36810SAnil Ravindranath { 485489a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 485589a36810SAnil Ravindranath void (*cmd_done) (struct pmcraid_cmd *) = pmcraid_complete_ioa_reset; 485689a36810SAnil Ravindranath 485789a36810SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 485889a36810SAnil Ravindranath 485989a36810SAnil Ravindranath ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); 486089a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_IOACMD; 486189a36810SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_SET_SUPPORTED_DEVICES; 486289a36810SAnil Ravindranath ioarcb->cdb[1] = ALL_DEVICES_SUPPORTED; 486389a36810SAnil Ravindranath 486489a36810SAnil Ravindranath /* If this was called as part of resource table reinitialization due to 486589a36810SAnil Ravindranath * lost CCN, it is enough to return the command block back to free pool 486689a36810SAnil Ravindranath * as part of set_supported_devs completion function. 486789a36810SAnil Ravindranath */ 486889a36810SAnil Ravindranath if (cmd->drv_inst->reinit_cfg_table) { 486989a36810SAnil Ravindranath cmd->drv_inst->reinit_cfg_table = 0; 487089a36810SAnil Ravindranath cmd->release = 1; 487189a36810SAnil Ravindranath cmd_done = pmcraid_reinit_cfgtable_done; 487289a36810SAnil Ravindranath } 487389a36810SAnil Ravindranath 487489a36810SAnil Ravindranath /* we will be done with the reset sequence after set supported devices, 487589a36810SAnil Ravindranath * setup the done function to return the command block back to free 487689a36810SAnil Ravindranath * pool 487789a36810SAnil Ravindranath */ 487889a36810SAnil Ravindranath pmcraid_send_cmd(cmd, 487989a36810SAnil Ravindranath cmd_done, 488089a36810SAnil Ravindranath PMCRAID_SET_SUP_DEV_TIMEOUT, 488189a36810SAnil Ravindranath pmcraid_timeout_handler); 488289a36810SAnil Ravindranath return; 488389a36810SAnil Ravindranath } 488489a36810SAnil Ravindranath 488589a36810SAnil Ravindranath /** 4886592488a3SAnil Ravindranath * pmcraid_set_timestamp - set the timestamp to IOAFP 4887592488a3SAnil Ravindranath * 4888592488a3SAnil Ravindranath * @cmd: pointer to pmcraid_cmd structure 4889592488a3SAnil Ravindranath * 4890592488a3SAnil Ravindranath * Return Value 4891592488a3SAnil Ravindranath * 0 for success or non-zero for failure cases 4892592488a3SAnil Ravindranath */ 4893592488a3SAnil Ravindranath static void pmcraid_set_timestamp(struct pmcraid_cmd *cmd) 4894592488a3SAnil Ravindranath { 4895592488a3SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 4896592488a3SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 4897592488a3SAnil Ravindranath __be32 time_stamp_len = cpu_to_be32(PMCRAID_TIMESTAMP_LEN); 4898b22ee87dSColin Ian King struct pmcraid_ioadl_desc *ioadl; 489945c80be6SArnd Bergmann u64 timestamp; 4900592488a3SAnil Ravindranath 49019c9bd593SAlison Schofield timestamp = ktime_get_real_seconds() * 1000; 4902592488a3SAnil Ravindranath 4903592488a3SAnil Ravindranath pinstance->timestamp_data->timestamp[0] = (__u8)(timestamp); 4904592488a3SAnil Ravindranath pinstance->timestamp_data->timestamp[1] = (__u8)((timestamp) >> 8); 4905592488a3SAnil Ravindranath pinstance->timestamp_data->timestamp[2] = (__u8)((timestamp) >> 16); 4906592488a3SAnil Ravindranath pinstance->timestamp_data->timestamp[3] = (__u8)((timestamp) >> 24); 4907592488a3SAnil Ravindranath pinstance->timestamp_data->timestamp[4] = (__u8)((timestamp) >> 32); 4908592488a3SAnil Ravindranath pinstance->timestamp_data->timestamp[5] = (__u8)((timestamp) >> 40); 4909592488a3SAnil Ravindranath 4910592488a3SAnil Ravindranath pmcraid_reinit_cmdblk(cmd); 4911592488a3SAnil Ravindranath ioarcb->request_type = REQ_TYPE_SCSI; 4912592488a3SAnil Ravindranath ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); 4913592488a3SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_SCSI_SET_TIMESTAMP; 4914592488a3SAnil Ravindranath ioarcb->cdb[1] = PMCRAID_SCSI_SERVICE_ACTION; 4915592488a3SAnil Ravindranath memcpy(&(ioarcb->cdb[6]), &time_stamp_len, sizeof(time_stamp_len)); 4916592488a3SAnil Ravindranath 4917592488a3SAnil Ravindranath ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + 4918592488a3SAnil Ravindranath offsetof(struct pmcraid_ioarcb, 4919592488a3SAnil Ravindranath add_data.u.ioadl[0])); 4920592488a3SAnil Ravindranath ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); 492145c80be6SArnd Bergmann ioarcb->ioarcb_bus_addr &= cpu_to_le64(~(0x1FULL)); 4922592488a3SAnil Ravindranath 4923592488a3SAnil Ravindranath ioarcb->request_flags0 |= NO_LINK_DESCS; 4924592488a3SAnil Ravindranath ioarcb->request_flags0 |= TRANSFER_DIR_WRITE; 4925592488a3SAnil Ravindranath ioarcb->data_transfer_length = 4926592488a3SAnil Ravindranath cpu_to_le32(sizeof(struct pmcraid_timestamp_data)); 4927592488a3SAnil Ravindranath ioadl = &(ioarcb->add_data.u.ioadl[0]); 4928592488a3SAnil Ravindranath ioadl->flags = IOADL_FLAGS_LAST_DESC; 4929592488a3SAnil Ravindranath ioadl->address = cpu_to_le64(pinstance->timestamp_data_baddr); 4930592488a3SAnil Ravindranath ioadl->data_len = cpu_to_le32(sizeof(struct pmcraid_timestamp_data)); 4931592488a3SAnil Ravindranath 4932592488a3SAnil Ravindranath if (!pinstance->timestamp_error) { 4933592488a3SAnil Ravindranath pinstance->timestamp_error = 0; 4934592488a3SAnil Ravindranath pmcraid_send_cmd(cmd, pmcraid_set_supported_devs, 4935592488a3SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler); 4936592488a3SAnil Ravindranath } else { 4937592488a3SAnil Ravindranath pmcraid_send_cmd(cmd, pmcraid_return_cmd, 4938592488a3SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler); 4939592488a3SAnil Ravindranath return; 4940592488a3SAnil Ravindranath } 4941592488a3SAnil Ravindranath } 4942592488a3SAnil Ravindranath 4943592488a3SAnil Ravindranath 4944592488a3SAnil Ravindranath /** 494589a36810SAnil Ravindranath * pmcraid_init_res_table - Initialize the resource table 494689a36810SAnil Ravindranath * @cmd: pointer to pmcraid command struct 494789a36810SAnil Ravindranath * 494889a36810SAnil Ravindranath * This function looks through the existing resource table, comparing 494989a36810SAnil Ravindranath * it with the config table. This function will take care of old/new 495089a36810SAnil Ravindranath * devices and schedule adding/removing them from the mid-layer 495189a36810SAnil Ravindranath * as appropriate. 495289a36810SAnil Ravindranath * 495389a36810SAnil Ravindranath * Return value 495489a36810SAnil Ravindranath * None 495589a36810SAnil Ravindranath */ 495689a36810SAnil Ravindranath static void pmcraid_init_res_table(struct pmcraid_cmd *cmd) 495789a36810SAnil Ravindranath { 495889a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 495989a36810SAnil Ravindranath struct pmcraid_resource_entry *res, *temp; 496089a36810SAnil Ravindranath struct pmcraid_config_table_entry *cfgte; 496189a36810SAnil Ravindranath unsigned long lock_flags; 496289a36810SAnil Ravindranath int found, rc, i; 4963c20c4267SAnil Ravindranath u16 fw_version; 496489a36810SAnil Ravindranath LIST_HEAD(old_res); 496589a36810SAnil Ravindranath 496689a36810SAnil Ravindranath if (pinstance->cfg_table->flags & MICROCODE_UPDATE_REQUIRED) 496734876402SAnil Ravindranath pmcraid_err("IOA requires microcode download\n"); 496889a36810SAnil Ravindranath 4969c20c4267SAnil Ravindranath fw_version = be16_to_cpu(pinstance->inq_data->fw_version); 4970c20c4267SAnil Ravindranath 497189a36810SAnil Ravindranath /* resource list is protected by pinstance->resource_lock. 497289a36810SAnil Ravindranath * init_res_table can be called from probe (user-thread) or runtime 497389a36810SAnil Ravindranath * reset (timer/tasklet) 497489a36810SAnil Ravindranath */ 497589a36810SAnil Ravindranath spin_lock_irqsave(&pinstance->resource_lock, lock_flags); 497689a36810SAnil Ravindranath 497789a36810SAnil Ravindranath list_for_each_entry_safe(res, temp, &pinstance->used_res_q, queue) 497889a36810SAnil Ravindranath list_move_tail(&res->queue, &old_res); 497989a36810SAnil Ravindranath 498045c80be6SArnd Bergmann for (i = 0; i < le16_to_cpu(pinstance->cfg_table->num_entries); i++) { 4981c20c4267SAnil Ravindranath if (be16_to_cpu(pinstance->inq_data->fw_version) <= 4982c20c4267SAnil Ravindranath PMCRAID_FW_VERSION_1) 498389a36810SAnil Ravindranath cfgte = &pinstance->cfg_table->entries[i]; 4984c20c4267SAnil Ravindranath else 4985c20c4267SAnil Ravindranath cfgte = (struct pmcraid_config_table_entry *) 4986c20c4267SAnil Ravindranath &pinstance->cfg_table->entries_ext[i]; 498789a36810SAnil Ravindranath 4988c20c4267SAnil Ravindranath if (!pmcraid_expose_resource(fw_version, cfgte)) 498989a36810SAnil Ravindranath continue; 499089a36810SAnil Ravindranath 499189a36810SAnil Ravindranath found = 0; 499289a36810SAnil Ravindranath 499389a36810SAnil Ravindranath /* If this entry was already detected and initialized */ 499489a36810SAnil Ravindranath list_for_each_entry_safe(res, temp, &old_res, queue) { 499589a36810SAnil Ravindranath 499689a36810SAnil Ravindranath rc = memcmp(&res->cfg_entry.resource_address, 499789a36810SAnil Ravindranath &cfgte->resource_address, 499889a36810SAnil Ravindranath sizeof(cfgte->resource_address)); 499989a36810SAnil Ravindranath if (!rc) { 500089a36810SAnil Ravindranath list_move_tail(&res->queue, 500189a36810SAnil Ravindranath &pinstance->used_res_q); 500289a36810SAnil Ravindranath found = 1; 500389a36810SAnil Ravindranath break; 500489a36810SAnil Ravindranath } 500589a36810SAnil Ravindranath } 500689a36810SAnil Ravindranath 500789a36810SAnil Ravindranath /* If this is new entry, initialize it and add it the queue */ 500889a36810SAnil Ravindranath if (!found) { 500989a36810SAnil Ravindranath 501089a36810SAnil Ravindranath if (list_empty(&pinstance->free_res_q)) { 501134876402SAnil Ravindranath pmcraid_err("Too many devices attached\n"); 501289a36810SAnil Ravindranath break; 501389a36810SAnil Ravindranath } 501489a36810SAnil Ravindranath 501589a36810SAnil Ravindranath found = 1; 501689a36810SAnil Ravindranath res = list_entry(pinstance->free_res_q.next, 501789a36810SAnil Ravindranath struct pmcraid_resource_entry, queue); 501889a36810SAnil Ravindranath 501989a36810SAnil Ravindranath res->scsi_dev = NULL; 502089a36810SAnil Ravindranath res->change_detected = RES_CHANGE_ADD; 502189a36810SAnil Ravindranath res->reset_progress = 0; 502289a36810SAnil Ravindranath list_move_tail(&res->queue, &pinstance->used_res_q); 502389a36810SAnil Ravindranath } 502489a36810SAnil Ravindranath 502589a36810SAnil Ravindranath /* copy new configuration table entry details into driver 502689a36810SAnil Ravindranath * maintained resource entry 502789a36810SAnil Ravindranath */ 502889a36810SAnil Ravindranath if (found) { 502989a36810SAnil Ravindranath memcpy(&res->cfg_entry, cfgte, 5030c20c4267SAnil Ravindranath pinstance->config_table_entry_size); 503189a36810SAnil Ravindranath pmcraid_info("New res type:%x, vset:%x, addr:%x:\n", 503289a36810SAnil Ravindranath res->cfg_entry.resource_type, 5033c20c4267SAnil Ravindranath (fw_version <= PMCRAID_FW_VERSION_1 ? 5034c20c4267SAnil Ravindranath res->cfg_entry.unique_flags1 : 503545c80be6SArnd Bergmann le16_to_cpu(res->cfg_entry.array_id) & 0xFF), 503689a36810SAnil Ravindranath le32_to_cpu(res->cfg_entry.resource_address)); 503789a36810SAnil Ravindranath } 503889a36810SAnil Ravindranath } 503989a36810SAnil Ravindranath 504089a36810SAnil Ravindranath /* Detect any deleted entries, mark them for deletion from mid-layer */ 504189a36810SAnil Ravindranath list_for_each_entry_safe(res, temp, &old_res, queue) { 504289a36810SAnil Ravindranath 504389a36810SAnil Ravindranath if (res->scsi_dev) { 504489a36810SAnil Ravindranath res->change_detected = RES_CHANGE_DEL; 504589a36810SAnil Ravindranath res->cfg_entry.resource_handle = 504689a36810SAnil Ravindranath PMCRAID_INVALID_RES_HANDLE; 504789a36810SAnil Ravindranath list_move_tail(&res->queue, &pinstance->used_res_q); 504889a36810SAnil Ravindranath } else { 504989a36810SAnil Ravindranath list_move_tail(&res->queue, &pinstance->free_res_q); 505089a36810SAnil Ravindranath } 505189a36810SAnil Ravindranath } 505289a36810SAnil Ravindranath 505389a36810SAnil Ravindranath /* release the resource list lock */ 505489a36810SAnil Ravindranath spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); 5055592488a3SAnil Ravindranath pmcraid_set_timestamp(cmd); 505689a36810SAnil Ravindranath } 505789a36810SAnil Ravindranath 505889a36810SAnil Ravindranath /** 505989a36810SAnil Ravindranath * pmcraid_querycfg - Send a Query IOA Config to the adapter. 506089a36810SAnil Ravindranath * @cmd: pointer pmcraid_cmd struct 506189a36810SAnil Ravindranath * 506289a36810SAnil Ravindranath * This function sends a Query IOA Configuration command to the adapter to 506389a36810SAnil Ravindranath * retrieve the IOA configuration table. 506489a36810SAnil Ravindranath * 506589a36810SAnil Ravindranath * Return value: 506689a36810SAnil Ravindranath * none 506789a36810SAnil Ravindranath */ 506889a36810SAnil Ravindranath static void pmcraid_querycfg(struct pmcraid_cmd *cmd) 506989a36810SAnil Ravindranath { 507089a36810SAnil Ravindranath struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; 5071b22ee87dSColin Ian King struct pmcraid_ioadl_desc *ioadl; 507289a36810SAnil Ravindranath struct pmcraid_instance *pinstance = cmd->drv_inst; 507345c80be6SArnd Bergmann __be32 cfg_table_size = cpu_to_be32(sizeof(struct pmcraid_config_table)); 507489a36810SAnil Ravindranath 5075c20c4267SAnil Ravindranath if (be16_to_cpu(pinstance->inq_data->fw_version) <= 5076c20c4267SAnil Ravindranath PMCRAID_FW_VERSION_1) 5077c20c4267SAnil Ravindranath pinstance->config_table_entry_size = 5078c20c4267SAnil Ravindranath sizeof(struct pmcraid_config_table_entry); 5079c20c4267SAnil Ravindranath else 5080c20c4267SAnil Ravindranath pinstance->config_table_entry_size = 5081c20c4267SAnil Ravindranath sizeof(struct pmcraid_config_table_entry_ext); 5082c20c4267SAnil Ravindranath 508389a36810SAnil Ravindranath ioarcb->request_type = REQ_TYPE_IOACMD; 508489a36810SAnil Ravindranath ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); 508589a36810SAnil Ravindranath 508689a36810SAnil Ravindranath ioarcb->cdb[0] = PMCRAID_QUERY_IOA_CONFIG; 508789a36810SAnil Ravindranath 508889a36810SAnil Ravindranath /* firmware requires 4-byte length field, specified in B.E format */ 508989a36810SAnil Ravindranath memcpy(&(ioarcb->cdb[10]), &cfg_table_size, sizeof(cfg_table_size)); 509089a36810SAnil Ravindranath 509189a36810SAnil Ravindranath /* Since entire config table can be described by single IOADL, it can 509289a36810SAnil Ravindranath * be part of IOARCB itself 509389a36810SAnil Ravindranath */ 509489a36810SAnil Ravindranath ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + 509589a36810SAnil Ravindranath offsetof(struct pmcraid_ioarcb, 509689a36810SAnil Ravindranath add_data.u.ioadl[0])); 509789a36810SAnil Ravindranath ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); 509845c80be6SArnd Bergmann ioarcb->ioarcb_bus_addr &= cpu_to_le64(~0x1FULL); 509989a36810SAnil Ravindranath 510089a36810SAnil Ravindranath ioarcb->request_flags0 |= NO_LINK_DESCS; 510189a36810SAnil Ravindranath ioarcb->data_transfer_length = 510289a36810SAnil Ravindranath cpu_to_le32(sizeof(struct pmcraid_config_table)); 510389a36810SAnil Ravindranath 510489a36810SAnil Ravindranath ioadl = &(ioarcb->add_data.u.ioadl[0]); 510588197966SAnil Ravindranath ioadl->flags = IOADL_FLAGS_LAST_DESC; 510689a36810SAnil Ravindranath ioadl->address = cpu_to_le64(pinstance->cfg_table_bus_addr); 510789a36810SAnil Ravindranath ioadl->data_len = cpu_to_le32(sizeof(struct pmcraid_config_table)); 510889a36810SAnil Ravindranath 510989a36810SAnil Ravindranath pmcraid_send_cmd(cmd, pmcraid_init_res_table, 511089a36810SAnil Ravindranath PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler); 511189a36810SAnil Ravindranath } 511289a36810SAnil Ravindranath 511389a36810SAnil Ravindranath 511489a36810SAnil Ravindranath /** 5115c20c4267SAnil Ravindranath * pmcraid_probe - PCI probe entry pointer for PMC MaxRAID controller driver 511689a36810SAnil Ravindranath * @pdev: pointer to pci device structure 511789a36810SAnil Ravindranath * @dev_id: pointer to device ids structure 511889a36810SAnil Ravindranath * 511989a36810SAnil Ravindranath * Return Value 512089a36810SAnil Ravindranath * returns 0 if the device is claimed and successfully configured. 512189a36810SAnil Ravindranath * returns non-zero error code in case of any failure 512289a36810SAnil Ravindranath */ 51236f039790SGreg Kroah-Hartman static int pmcraid_probe(struct pci_dev *pdev, 51246f039790SGreg Kroah-Hartman const struct pci_device_id *dev_id) 512589a36810SAnil Ravindranath { 512689a36810SAnil Ravindranath struct pmcraid_instance *pinstance; 512789a36810SAnil Ravindranath struct Scsi_Host *host; 512889a36810SAnil Ravindranath void __iomem *mapped_pci_addr; 512989a36810SAnil Ravindranath int rc = PCIBIOS_SUCCESSFUL; 513089a36810SAnil Ravindranath 513189a36810SAnil Ravindranath if (atomic_read(&pmcraid_adapter_count) >= PMCRAID_MAX_ADAPTERS) { 513289a36810SAnil Ravindranath pmcraid_err 513389a36810SAnil Ravindranath ("maximum number(%d) of supported adapters reached\n", 513489a36810SAnil Ravindranath atomic_read(&pmcraid_adapter_count)); 513589a36810SAnil Ravindranath return -ENOMEM; 513689a36810SAnil Ravindranath } 513789a36810SAnil Ravindranath 513889a36810SAnil Ravindranath atomic_inc(&pmcraid_adapter_count); 513989a36810SAnil Ravindranath rc = pci_enable_device(pdev); 514089a36810SAnil Ravindranath 514189a36810SAnil Ravindranath if (rc) { 514289a36810SAnil Ravindranath dev_err(&pdev->dev, "Cannot enable adapter\n"); 514389a36810SAnil Ravindranath atomic_dec(&pmcraid_adapter_count); 514489a36810SAnil Ravindranath return rc; 514589a36810SAnil Ravindranath } 514689a36810SAnil Ravindranath 514789a36810SAnil Ravindranath dev_info(&pdev->dev, 514889a36810SAnil Ravindranath "Found new IOA(%x:%x), Total IOA count: %d\n", 514989a36810SAnil Ravindranath pdev->vendor, pdev->device, 515089a36810SAnil Ravindranath atomic_read(&pmcraid_adapter_count)); 515189a36810SAnil Ravindranath 515289a36810SAnil Ravindranath rc = pci_request_regions(pdev, PMCRAID_DRIVER_NAME); 515389a36810SAnil Ravindranath 515489a36810SAnil Ravindranath if (rc < 0) { 515589a36810SAnil Ravindranath dev_err(&pdev->dev, 515689a36810SAnil Ravindranath "Couldn't register memory range of registers\n"); 515789a36810SAnil Ravindranath goto out_disable_device; 515889a36810SAnil Ravindranath } 515989a36810SAnil Ravindranath 516089a36810SAnil Ravindranath mapped_pci_addr = pci_iomap(pdev, 0, 0); 516189a36810SAnil Ravindranath 516289a36810SAnil Ravindranath if (!mapped_pci_addr) { 516389a36810SAnil Ravindranath dev_err(&pdev->dev, "Couldn't map PCI registers memory\n"); 516489a36810SAnil Ravindranath rc = -ENOMEM; 516589a36810SAnil Ravindranath goto out_release_regions; 516689a36810SAnil Ravindranath } 516789a36810SAnil Ravindranath 516889a36810SAnil Ravindranath pci_set_master(pdev); 516989a36810SAnil Ravindranath 517089a36810SAnil Ravindranath /* Firmware requires the system bus address of IOARCB to be within 517189a36810SAnil Ravindranath * 32-bit addressable range though it has 64-bit IOARRIN register. 517289a36810SAnil Ravindranath * However, firmware supports 64-bit streaming DMA buffers, whereas 5173371a6c32SChristoph Hellwig * coherent buffers are to be 32-bit. Since dma_alloc_coherent always 517489a36810SAnil Ravindranath * returns memory within 4GB (if not, change this logic), coherent 517525985edcSLucas De Marchi * buffers are within firmware acceptable address ranges. 517689a36810SAnil Ravindranath */ 5177371a6c32SChristoph Hellwig if (sizeof(dma_addr_t) == 4 || 5178371a6c32SChristoph Hellwig dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) 5179371a6c32SChristoph Hellwig rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); 518089a36810SAnil Ravindranath 518189a36810SAnil Ravindranath /* firmware expects 32-bit DMA addresses for IOARRIN register; set 32 5182371a6c32SChristoph Hellwig * bit mask for dma_alloc_coherent to return addresses within 4GB 518389a36810SAnil Ravindranath */ 518489a36810SAnil Ravindranath if (rc == 0) 5185371a6c32SChristoph Hellwig rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); 518689a36810SAnil Ravindranath 518789a36810SAnil Ravindranath if (rc != 0) { 518889a36810SAnil Ravindranath dev_err(&pdev->dev, "Failed to set PCI DMA mask\n"); 518989a36810SAnil Ravindranath goto cleanup_nomem; 519089a36810SAnil Ravindranath } 519189a36810SAnil Ravindranath 519289a36810SAnil Ravindranath host = scsi_host_alloc(&pmcraid_host_template, 519389a36810SAnil Ravindranath sizeof(struct pmcraid_instance)); 519489a36810SAnil Ravindranath 519589a36810SAnil Ravindranath if (!host) { 519689a36810SAnil Ravindranath dev_err(&pdev->dev, "scsi_host_alloc failed!\n"); 519789a36810SAnil Ravindranath rc = -ENOMEM; 519889a36810SAnil Ravindranath goto cleanup_nomem; 519989a36810SAnil Ravindranath } 520089a36810SAnil Ravindranath 520189a36810SAnil Ravindranath host->max_id = PMCRAID_MAX_NUM_TARGETS_PER_BUS; 520289a36810SAnil Ravindranath host->max_lun = PMCRAID_MAX_NUM_LUNS_PER_TARGET; 520389a36810SAnil Ravindranath host->unique_id = host->host_no; 520489a36810SAnil Ravindranath host->max_channel = PMCRAID_MAX_BUS_TO_SCAN; 520589a36810SAnil Ravindranath host->max_cmd_len = PMCRAID_MAX_CDB_LEN; 520689a36810SAnil Ravindranath 520789a36810SAnil Ravindranath /* zero out entire instance structure */ 520889a36810SAnil Ravindranath pinstance = (struct pmcraid_instance *)host->hostdata; 520989a36810SAnil Ravindranath memset(pinstance, 0, sizeof(*pinstance)); 521089a36810SAnil Ravindranath 521189a36810SAnil Ravindranath pinstance->chip_cfg = 521289a36810SAnil Ravindranath (struct pmcraid_chip_details *)(dev_id->driver_data); 521389a36810SAnil Ravindranath 521489a36810SAnil Ravindranath rc = pmcraid_init_instance(pdev, host, mapped_pci_addr); 521589a36810SAnil Ravindranath 521689a36810SAnil Ravindranath if (rc < 0) { 521789a36810SAnil Ravindranath dev_err(&pdev->dev, "failed to initialize adapter instance\n"); 521889a36810SAnil Ravindranath goto out_scsi_host_put; 521989a36810SAnil Ravindranath } 522089a36810SAnil Ravindranath 522189a36810SAnil Ravindranath pci_set_drvdata(pdev, pinstance); 522289a36810SAnil Ravindranath 522389a36810SAnil Ravindranath /* Save PCI config-space for use following the reset */ 522489a36810SAnil Ravindranath rc = pci_save_state(pinstance->pdev); 522589a36810SAnil Ravindranath 522689a36810SAnil Ravindranath if (rc != 0) { 522789a36810SAnil Ravindranath dev_err(&pdev->dev, "Failed to save PCI config space\n"); 522889a36810SAnil Ravindranath goto out_scsi_host_put; 522989a36810SAnil Ravindranath } 523089a36810SAnil Ravindranath 523189a36810SAnil Ravindranath pmcraid_disable_interrupts(pinstance, ~0); 523289a36810SAnil Ravindranath 523389a36810SAnil Ravindranath rc = pmcraid_register_interrupt_handler(pinstance); 523489a36810SAnil Ravindranath 523589a36810SAnil Ravindranath if (rc) { 523634876402SAnil Ravindranath dev_err(&pdev->dev, "couldn't register interrupt handler\n"); 523789a36810SAnil Ravindranath goto out_scsi_host_put; 523889a36810SAnil Ravindranath } 523989a36810SAnil Ravindranath 524089a36810SAnil Ravindranath pmcraid_init_tasklets(pinstance); 524189a36810SAnil Ravindranath 524289a36810SAnil Ravindranath /* allocate verious buffers used by LLD.*/ 524389a36810SAnil Ravindranath rc = pmcraid_init_buffers(pinstance); 524489a36810SAnil Ravindranath 524589a36810SAnil Ravindranath if (rc) { 524689a36810SAnil Ravindranath pmcraid_err("couldn't allocate memory blocks\n"); 524789a36810SAnil Ravindranath goto out_unregister_isr; 524889a36810SAnil Ravindranath } 524989a36810SAnil Ravindranath 525089a36810SAnil Ravindranath /* check the reset type required */ 525189a36810SAnil Ravindranath pmcraid_reset_type(pinstance); 525289a36810SAnil Ravindranath 525389a36810SAnil Ravindranath pmcraid_enable_interrupts(pinstance, PMCRAID_PCI_INTERRUPTS); 525489a36810SAnil Ravindranath 525589a36810SAnil Ravindranath /* Start IOA firmware initialization and bring card to Operational 525689a36810SAnil Ravindranath * state. 525789a36810SAnil Ravindranath */ 525889a36810SAnil Ravindranath pmcraid_info("starting IOA initialization sequence\n"); 525989a36810SAnil Ravindranath if (pmcraid_reset_bringup(pinstance)) { 526034876402SAnil Ravindranath dev_err(&pdev->dev, "couldn't initialize IOA\n"); 526189a36810SAnil Ravindranath rc = 1; 526289a36810SAnil Ravindranath goto out_release_bufs; 526389a36810SAnil Ravindranath } 526489a36810SAnil Ravindranath 526589a36810SAnil Ravindranath /* Add adapter instance into mid-layer list */ 526689a36810SAnil Ravindranath rc = scsi_add_host(pinstance->host, &pdev->dev); 526789a36810SAnil Ravindranath if (rc != 0) { 526889a36810SAnil Ravindranath pmcraid_err("couldn't add host into mid-layer: %d\n", rc); 526989a36810SAnil Ravindranath goto out_release_bufs; 527089a36810SAnil Ravindranath } 527189a36810SAnil Ravindranath 527289a36810SAnil Ravindranath scsi_scan_host(pinstance->host); 527389a36810SAnil Ravindranath 527489a36810SAnil Ravindranath rc = pmcraid_setup_chrdev(pinstance); 527589a36810SAnil Ravindranath 527689a36810SAnil Ravindranath if (rc != 0) { 527789a36810SAnil Ravindranath pmcraid_err("couldn't create mgmt interface, error: %x\n", 527889a36810SAnil Ravindranath rc); 527989a36810SAnil Ravindranath goto out_remove_host; 528089a36810SAnil Ravindranath } 528189a36810SAnil Ravindranath 528289a36810SAnil Ravindranath /* Schedule worker thread to handle CCN and take care of adding and 528389a36810SAnil Ravindranath * removing devices to OS 528489a36810SAnil Ravindranath */ 528589a36810SAnil Ravindranath atomic_set(&pinstance->expose_resources, 1); 528689a36810SAnil Ravindranath schedule_work(&pinstance->worker_q); 528789a36810SAnil Ravindranath return rc; 528889a36810SAnil Ravindranath 528989a36810SAnil Ravindranath out_remove_host: 529089a36810SAnil Ravindranath scsi_remove_host(host); 529189a36810SAnil Ravindranath 529289a36810SAnil Ravindranath out_release_bufs: 529389a36810SAnil Ravindranath pmcraid_release_buffers(pinstance); 529489a36810SAnil Ravindranath 529589a36810SAnil Ravindranath out_unregister_isr: 529689a36810SAnil Ravindranath pmcraid_kill_tasklets(pinstance); 529789a36810SAnil Ravindranath pmcraid_unregister_interrupt_handler(pinstance); 529889a36810SAnil Ravindranath 529989a36810SAnil Ravindranath out_scsi_host_put: 530089a36810SAnil Ravindranath scsi_host_put(host); 530189a36810SAnil Ravindranath 530289a36810SAnil Ravindranath cleanup_nomem: 530389a36810SAnil Ravindranath iounmap(mapped_pci_addr); 530489a36810SAnil Ravindranath 530589a36810SAnil Ravindranath out_release_regions: 530689a36810SAnil Ravindranath pci_release_regions(pdev); 530789a36810SAnil Ravindranath 530889a36810SAnil Ravindranath out_disable_device: 530989a36810SAnil Ravindranath atomic_dec(&pmcraid_adapter_count); 531089a36810SAnil Ravindranath pci_disable_device(pdev); 531189a36810SAnil Ravindranath return -ENODEV; 531289a36810SAnil Ravindranath } 531389a36810SAnil Ravindranath 5314ac85cca3SVaibhav Gupta static SIMPLE_DEV_PM_OPS(pmcraid_pm_ops, pmcraid_suspend, pmcraid_resume); 5315ac85cca3SVaibhav Gupta 531689a36810SAnil Ravindranath /* 531718daf910SChristophe JAILLET * PCI driver structure of pmcraid driver 531889a36810SAnil Ravindranath */ 531989a36810SAnil Ravindranath static struct pci_driver pmcraid_driver = { 532089a36810SAnil Ravindranath .name = PMCRAID_DRIVER_NAME, 532189a36810SAnil Ravindranath .id_table = pmcraid_pci_table, 532289a36810SAnil Ravindranath .probe = pmcraid_probe, 532389a36810SAnil Ravindranath .remove = pmcraid_remove, 5324ac85cca3SVaibhav Gupta .driver.pm = &pmcraid_pm_ops, 532589a36810SAnil Ravindranath .shutdown = pmcraid_shutdown 532689a36810SAnil Ravindranath }; 532789a36810SAnil Ravindranath 532889a36810SAnil Ravindranath /** 532989a36810SAnil Ravindranath * pmcraid_init - module load entry point 533089a36810SAnil Ravindranath */ 533189a36810SAnil Ravindranath static int __init pmcraid_init(void) 533289a36810SAnil Ravindranath { 533389a36810SAnil Ravindranath dev_t dev; 533489a36810SAnil Ravindranath int error; 533589a36810SAnil Ravindranath 5336a1b66665SMichal Marek pmcraid_info("%s Device Driver version: %s\n", 5337a1b66665SMichal Marek PMCRAID_DRIVER_NAME, PMCRAID_DRIVER_VERSION); 533889a36810SAnil Ravindranath 533989a36810SAnil Ravindranath error = alloc_chrdev_region(&dev, 0, 534089a36810SAnil Ravindranath PMCRAID_MAX_ADAPTERS, 534189a36810SAnil Ravindranath PMCRAID_DEVFILE); 534289a36810SAnil Ravindranath 534389a36810SAnil Ravindranath if (error) { 534489a36810SAnil Ravindranath pmcraid_err("failed to get a major number for adapters\n"); 534589a36810SAnil Ravindranath goto out_init; 534689a36810SAnil Ravindranath } 534789a36810SAnil Ravindranath 534889a36810SAnil Ravindranath pmcraid_major = MAJOR(dev); 534989a36810SAnil Ravindranath pmcraid_class = class_create(THIS_MODULE, PMCRAID_DEVFILE); 535089a36810SAnil Ravindranath 535189a36810SAnil Ravindranath if (IS_ERR(pmcraid_class)) { 535289a36810SAnil Ravindranath error = PTR_ERR(pmcraid_class); 5353278cee05SMasanari Iida pmcraid_err("failed to register with sysfs, error = %x\n", 535489a36810SAnil Ravindranath error); 535589a36810SAnil Ravindranath goto out_unreg_chrdev; 535689a36810SAnil Ravindranath } 535789a36810SAnil Ravindranath 535889a36810SAnil Ravindranath error = pmcraid_netlink_init(); 535989a36810SAnil Ravindranath 53602d76a247SQuentin Lambert if (error) { 53612d76a247SQuentin Lambert class_destroy(pmcraid_class); 536289a36810SAnil Ravindranath goto out_unreg_chrdev; 53632d76a247SQuentin Lambert } 536489a36810SAnil Ravindranath 536589a36810SAnil Ravindranath error = pci_register_driver(&pmcraid_driver); 536689a36810SAnil Ravindranath 536789a36810SAnil Ravindranath if (error == 0) 536889a36810SAnil Ravindranath goto out_init; 536989a36810SAnil Ravindranath 537089a36810SAnil Ravindranath pmcraid_err("failed to register pmcraid driver, error = %x\n", 537189a36810SAnil Ravindranath error); 537289a36810SAnil Ravindranath class_destroy(pmcraid_class); 537389a36810SAnil Ravindranath pmcraid_netlink_release(); 537489a36810SAnil Ravindranath 537589a36810SAnil Ravindranath out_unreg_chrdev: 537689a36810SAnil Ravindranath unregister_chrdev_region(MKDEV(pmcraid_major, 0), PMCRAID_MAX_ADAPTERS); 537734876402SAnil Ravindranath 537889a36810SAnil Ravindranath out_init: 537989a36810SAnil Ravindranath return error; 538089a36810SAnil Ravindranath } 538189a36810SAnil Ravindranath 538289a36810SAnil Ravindranath /** 538389a36810SAnil Ravindranath * pmcraid_exit - module unload entry point 538489a36810SAnil Ravindranath */ 538589a36810SAnil Ravindranath static void __exit pmcraid_exit(void) 538689a36810SAnil Ravindranath { 538789a36810SAnil Ravindranath pmcraid_netlink_release(); 538889a36810SAnil Ravindranath unregister_chrdev_region(MKDEV(pmcraid_major, 0), 538989a36810SAnil Ravindranath PMCRAID_MAX_ADAPTERS); 539089a36810SAnil Ravindranath pci_unregister_driver(&pmcraid_driver); 5391592488a3SAnil Ravindranath class_destroy(pmcraid_class); 539289a36810SAnil Ravindranath } 539389a36810SAnil Ravindranath 539489a36810SAnil Ravindranath module_init(pmcraid_init); 539589a36810SAnil Ravindranath module_exit(pmcraid_exit); 5396