summaryrefslogtreecommitdiff
path: root/drivers/scsi/pm8001/pm8001_init.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/pm8001/pm8001_init.c')
-rw-r--r--drivers/scsi/pm8001/pm8001_init.c504
1 files changed, 267 insertions, 237 deletions
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index d8a2121cb8d9..9acca83d6958 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -43,7 +43,8 @@
#include "pm8001_chips.h"
#include "pm80xx_hwi.h"
-static ulong logging_level = PM8001_FAIL_LOGGING | PM8001_IOERR_LOGGING;
+static ulong logging_level = PM8001_FAIL_LOGGING | PM8001_IOERR_LOGGING |
+ PM8001_EVENT_LOGGING | PM8001_INIT_LOGGING;
module_param(logging_level, ulong, 0644);
MODULE_PARM_DESC(logging_level, " bits for enabling logging info.");
@@ -55,8 +56,24 @@ MODULE_PARM_DESC(link_rate, "Enable link rate.\n"
" 4: Link rate 6.0G\n"
" 8: Link rate 12.0G\n");
+bool pm8001_use_msix = true;
+module_param_named(use_msix, pm8001_use_msix, bool, 0444);
+MODULE_PARM_DESC(zoned, "Use MSIX interrupts. Default: true");
+
+static bool pm8001_use_tasklet = true;
+module_param_named(use_tasklet, pm8001_use_tasklet, bool, 0444);
+MODULE_PARM_DESC(zoned, "Use MSIX interrupts. Default: true");
+
+static bool pm8001_read_wwn = true;
+module_param_named(read_wwn, pm8001_read_wwn, bool, 0444);
+MODULE_PARM_DESC(zoned, "Get WWN from the controller. Default: true");
+
+uint pcs_event_log_severity = 0x03;
+module_param(pcs_event_log_severity, int, 0644);
+MODULE_PARM_DESC(pcs_event_log_severity, "PCS event log severity level");
+
static struct scsi_transport_template *pm8001_stt;
-static int pm8001_init_ccb_tag(struct pm8001_hba_info *, struct Scsi_Host *, struct pci_dev *);
+static int pm8001_init_ccb_tag(struct pm8001_hba_info *);
/*
* chip info structure to identify chip key functionality as
@@ -81,34 +98,35 @@ LIST_HEAD(hba_list);
struct workqueue_struct *pm8001_wq;
+static void pm8001_map_queues(struct Scsi_Host *shost)
+{
+ struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+ struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
+ struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT];
+
+ if (pm8001_ha->number_of_intr > 1) {
+ blk_mq_map_hw_queues(qmap, &pm8001_ha->pdev->dev, 1);
+ return;
+ }
+
+ blk_mq_map_queues(qmap);
+}
+
/*
* The main structure which LLDD must register for scsi core.
*/
-static struct scsi_host_template pm8001_sht = {
- .module = THIS_MODULE,
- .name = DRV_NAME,
- .queuecommand = sas_queuecommand,
- .dma_need_drain = ata_scsi_dma_need_drain,
- .target_alloc = sas_target_alloc,
- .slave_configure = sas_slave_configure,
+static const struct scsi_host_template pm8001_sht = {
+ LIBSAS_SHT_BASE
.scan_finished = pm8001_scan_finished,
.scan_start = pm8001_scan_start,
- .change_queue_depth = sas_change_queue_depth,
- .bios_param = sas_bios_param,
.can_queue = 1,
- .this_id = -1,
.sg_tablesize = PM8001_MAX_DMA_SG,
- .max_sectors = SCSI_DEFAULT_MAX_SECTORS,
- .eh_device_reset_handler = sas_eh_device_reset_handler,
- .eh_target_reset_handler = sas_eh_target_reset_handler,
- .slave_alloc = sas_slave_alloc,
- .target_destroy = sas_target_destroy,
- .ioctl = sas_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = sas_ioctl,
-#endif
+ .max_sectors = PM8001_MAX_SECTORS,
.shost_groups = pm8001_host_groups,
+ .sdev_groups = pm8001_sdev_groups,
.track_queue_depth = 1,
+ .cmd_per_lun = 32,
+ .map_queues = pm8001_map_queues,
};
/*
@@ -122,13 +140,14 @@ static struct sas_domain_function_template pm8001_transport_ops = {
.lldd_control_phy = pm8001_phy_control,
.lldd_abort_task = pm8001_abort_task,
- .lldd_abort_task_set = pm8001_abort_task_set,
- .lldd_clear_aca = pm8001_clear_aca,
+ .lldd_abort_task_set = sas_abort_task_set,
.lldd_clear_task_set = pm8001_clear_task_set,
.lldd_I_T_nexus_reset = pm8001_I_T_nexus_reset,
.lldd_lu_reset = pm8001_lu_reset,
.lldd_query_task = pm8001_query_task,
.lldd_port_formed = pm8001_port_formed,
+ .lldd_tmf_exec_complete = pm8001_setds_completion,
+ .lldd_tmf_aborted = pm8001_tmf_aborted,
};
/**
@@ -142,11 +161,11 @@ static void pm8001_phy_init(struct pm8001_hba_info *pm8001_ha, int phy_id)
struct asd_sas_phy *sas_phy = &phy->sas_phy;
phy->phy_state = PHY_LINK_DISABLE;
phy->pm8001_ha = pm8001_ha;
+ phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
+ phy->maximum_linkrate = SAS_LINK_RATE_6_0_GBPS;
sas_phy->enabled = (phy_id < pm8001_ha->chip->n_phy) ? 1 : 0;
- sas_phy->class = SAS;
sas_phy->iproto = SAS_PROTOCOL_ALL;
sas_phy->tproto = 0;
- sas_phy->type = PHY_TYPE_PHYSICAL;
sas_phy->role = PHY_ROLE_INITIATOR;
sas_phy->oob_mode = OOB_NOT_CONNECTED;
sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN;
@@ -179,12 +198,10 @@ static void pm8001_free(struct pm8001_hba_info *pm8001_ha)
}
PM8001_CHIP_DISP->chip_iounmap(pm8001_ha);
flush_workqueue(pm8001_wq);
- bitmap_free(pm8001_ha->tags);
+ bitmap_free(pm8001_ha->rsvd_tags);
kfree(pm8001_ha);
}
-#ifdef PM8001_USE_TASKLET
-
/**
* pm8001_tasklet() - tasklet for 64 msi-x interrupt handler
* @opaque: the passed general host adapter struct
@@ -192,16 +209,67 @@ static void pm8001_free(struct pm8001_hba_info *pm8001_ha)
*/
static void pm8001_tasklet(unsigned long opaque)
{
- struct pm8001_hba_info *pm8001_ha;
- struct isr_param *irq_vector;
+ struct isr_param *irq_vector = (struct isr_param *)opaque;
+ struct pm8001_hba_info *pm8001_ha = irq_vector->drv_inst;
+
+ if (WARN_ON_ONCE(!pm8001_ha))
+ return;
- irq_vector = (struct isr_param *)opaque;
- pm8001_ha = irq_vector->drv_inst;
- if (unlikely(!pm8001_ha))
- BUG_ON(1);
PM8001_CHIP_DISP->isr(pm8001_ha, irq_vector->irq_id);
}
-#endif
+
+static void pm8001_init_tasklet(struct pm8001_hba_info *pm8001_ha)
+{
+ int i;
+
+ if (!pm8001_use_tasklet)
+ return;
+
+ /* Tasklet for non msi-x interrupt handler */
+ if ((!pm8001_ha->pdev->msix_cap || !pci_msi_enabled()) ||
+ (pm8001_ha->chip_id == chip_8001)) {
+ tasklet_init(&pm8001_ha->tasklet[0], pm8001_tasklet,
+ (unsigned long)&(pm8001_ha->irq_vector[0]));
+ return;
+ }
+ for (i = 0; i < PM8001_MAX_MSIX_VEC; i++)
+ tasklet_init(&pm8001_ha->tasklet[i], pm8001_tasklet,
+ (unsigned long)&(pm8001_ha->irq_vector[i]));
+}
+
+static void pm8001_kill_tasklet(struct pm8001_hba_info *pm8001_ha)
+{
+ int i;
+
+ if (!pm8001_use_tasklet)
+ return;
+
+ /* For non-msix and msix interrupts */
+ if ((!pm8001_ha->pdev->msix_cap || !pci_msi_enabled()) ||
+ (pm8001_ha->chip_id == chip_8001)) {
+ tasklet_kill(&pm8001_ha->tasklet[0]);
+ return;
+ }
+
+ for (i = 0; i < PM8001_MAX_MSIX_VEC; i++)
+ tasklet_kill(&pm8001_ha->tasklet[i]);
+}
+
+static irqreturn_t pm8001_handle_irq(struct pm8001_hba_info *pm8001_ha,
+ int irq)
+{
+ if (unlikely(!pm8001_ha))
+ return IRQ_NONE;
+
+ if (!PM8001_CHIP_DISP->is_our_interrupt(pm8001_ha))
+ return IRQ_NONE;
+
+ if (!pm8001_use_tasklet)
+ return PM8001_CHIP_DISP->isr(pm8001_ha, irq);
+
+ tasklet_schedule(&pm8001_ha->tasklet[irq]);
+ return IRQ_HANDLED;
+}
/**
* pm8001_interrupt_handler_msix - main MSIX interrupt handler.
@@ -213,22 +281,10 @@ static void pm8001_tasklet(unsigned long opaque)
*/
static irqreturn_t pm8001_interrupt_handler_msix(int irq, void *opaque)
{
- struct isr_param *irq_vector;
- struct pm8001_hba_info *pm8001_ha;
- irqreturn_t ret = IRQ_HANDLED;
- irq_vector = (struct isr_param *)opaque;
- pm8001_ha = irq_vector->drv_inst;
+ struct isr_param *irq_vector = (struct isr_param *)opaque;
+ struct pm8001_hba_info *pm8001_ha = irq_vector->drv_inst;
- if (unlikely(!pm8001_ha))
- return IRQ_NONE;
- if (!PM8001_CHIP_DISP->is_our_interrupt(pm8001_ha))
- return IRQ_NONE;
-#ifdef PM8001_USE_TASKLET
- tasklet_schedule(&pm8001_ha->tasklet[irq_vector->irq_id]);
-#else
- ret = PM8001_CHIP_DISP->isr(pm8001_ha, irq_vector->irq_id);
-#endif
- return ret;
+ return pm8001_handle_irq(pm8001_ha, irq_vector->irq_id);
}
/**
@@ -239,25 +295,14 @@ static irqreturn_t pm8001_interrupt_handler_msix(int irq, void *opaque)
static irqreturn_t pm8001_interrupt_handler_intx(int irq, void *dev_id)
{
- struct pm8001_hba_info *pm8001_ha;
- irqreturn_t ret = IRQ_HANDLED;
struct sas_ha_struct *sha = dev_id;
- pm8001_ha = sha->lldd_ha;
- if (unlikely(!pm8001_ha))
- return IRQ_NONE;
- if (!PM8001_CHIP_DISP->is_our_interrupt(pm8001_ha))
- return IRQ_NONE;
+ struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
-#ifdef PM8001_USE_TASKLET
- tasklet_schedule(&pm8001_ha->tasklet[0]);
-#else
- ret = PM8001_CHIP_DISP->isr(pm8001_ha, 0);
-#endif
- return ret;
+ return pm8001_handle_irq(pm8001_ha, 0);
}
-static u32 pm8001_setup_irq(struct pm8001_hba_info *pm8001_ha);
static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha);
+static void pm8001_free_irq(struct pm8001_hba_info *pm8001_ha);
/**
* pm8001_alloc - initiate our hba structure and 6 DMAs area.
@@ -277,13 +322,6 @@ static int pm8001_alloc(struct pm8001_hba_info *pm8001_ha,
pm8001_dbg(pm8001_ha, INIT, "pm8001_alloc: PHY:%x\n",
pm8001_ha->chip->n_phy);
- /* Setup Interrupt */
- rc = pm8001_setup_irq(pm8001_ha);
- if (rc) {
- pm8001_dbg(pm8001_ha, FAIL,
- "pm8001_setup_irq failed [ret: %d]\n", rc);
- goto err_out;
- }
/* Request Interrupt */
rc = pm8001_request_irq(pm8001_ha);
if (rc)
@@ -414,13 +452,8 @@ static int pm8001_alloc(struct pm8001_hba_info *pm8001_ha,
}
for (i = 0; i < PM8001_MAX_DEVICES; i++) {
pm8001_ha->devices[i].dev_type = SAS_PHY_UNUSED;
- pm8001_ha->devices[i].id = i;
- pm8001_ha->devices[i].device_id = PM8001_MAX_DEVICES;
- atomic_set(&pm8001_ha->devices[i].running_req, 0);
}
pm8001_ha->flags = PM8001F_INIT_TIME;
- /* Initialize tags */
- pm8001_tag_init(pm8001_ha);
return 0;
err_out_nodev:
@@ -504,7 +537,6 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev,
{
struct pm8001_hba_info *pm8001_ha;
struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
- int j;
pm8001_ha = sha->lldd_ha;
if (!pm8001_ha)
@@ -520,6 +552,7 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev,
pm8001_ha->id = pm8001_id++;
pm8001_ha->logging_level = logging_level;
pm8001_ha->non_fatal_count = 0;
+ mutex_init(&pm8001_ha->iop_log_lock);
if (link_rate >= 1 && link_rate <= 15)
pm8001_ha->link_rate = (link_rate << 8);
else {
@@ -535,17 +568,8 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev,
else
pm8001_ha->iomb_size = IOMB_SIZE_SPC;
-#ifdef PM8001_USE_TASKLET
- /* Tasklet for non msi-x interrupt handler */
- if ((!pdev->msix_cap || !pci_msi_enabled())
- || (pm8001_ha->chip_id == chip_8001))
- tasklet_init(&pm8001_ha->tasklet[0], pm8001_tasklet,
- (unsigned long)&(pm8001_ha->irq_vector[0]));
- else
- for (j = 0; j < PM8001_MAX_MSIX_VEC; j++)
- tasklet_init(&pm8001_ha->tasklet[j], pm8001_tasklet,
- (unsigned long)&(pm8001_ha->irq_vector[j]));
-#endif
+ pm8001_init_tasklet(pm8001_ha);
+
if (pm8001_ioremap(pm8001_ha))
goto failed_pci_alloc;
if (!pm8001_alloc(pm8001_ha, ent))
@@ -604,12 +628,8 @@ static int pm8001_prep_sas_ha_init(struct Scsi_Host *shost,
shost->transportt = pm8001_stt;
shost->max_id = PM8001_MAX_DEVICES;
- shost->max_lun = 8;
- shost->max_channel = 0;
shost->unique_id = pm8001_id;
shost->max_cmd_len = 16;
- shost->can_queue = PM8001_CAN_QUEUE;
- shost->cmd_per_lun = 32;
return 0;
exit_free1:
kfree(arr_port);
@@ -641,10 +661,9 @@ static void pm8001_post_sas_ha_init(struct Scsi_Host *shost,
sha->sas_ha_name = DRV_NAME;
sha->dev = pm8001_ha->dev;
sha->strict_wide_ports = 1;
- sha->lldd_module = THIS_MODULE;
sha->sas_addr = &pm8001_ha->sas_addr[0];
sha->num_phys = chip_info->n_phy;
- sha->core.shost = shost;
+ sha->shost = shost;
}
/**
@@ -654,19 +673,36 @@ static void pm8001_post_sas_ha_init(struct Scsi_Host *shost,
* Currently we just set the fixed SAS address to our HBA, for manufacture,
* it should read from the EEPROM
*/
-static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
+static int pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
{
- u8 i, j;
- u8 sas_add[8];
-#ifdef PM8001_READ_VPD
- /* For new SPC controllers WWN is stored in flash vpd
- * For SPC/SPCve controllers WWN is stored in EEPROM
- * For Older SPC WWN is stored in NVMD
- */
DECLARE_COMPLETION_ONSTACK(completion);
struct pm8001_ioctl_payload payload;
+ unsigned long time_remaining;
+ u8 sas_add[8];
u16 deviceid;
int rc;
+ u8 i, j;
+
+ if (!pm8001_read_wwn) {
+ __be64 dev_sas_addr = cpu_to_be64(0x50010c600047f9d0ULL);
+
+ for (i = 0; i < pm8001_ha->chip->n_phy; i++)
+ memcpy(&pm8001_ha->phy[i].dev_sas_addr, &dev_sas_addr,
+ SAS_ADDR_SIZE);
+ memcpy(pm8001_ha->sas_addr, &pm8001_ha->phy[0].dev_sas_addr,
+ SAS_ADDR_SIZE);
+ return 0;
+ }
+
+ /*
+ * For new SPC controllers WWN is stored in flash vpd. For SPC/SPCve
+ * controllers WWN is stored in EEPROM. And for Older SPC WWN is stored
+ * in NVMD.
+ */
+ if (PM8001_CHIP_DISP->fatal_errors(pm8001_ha)) {
+ pm8001_dbg(pm8001_ha, FAIL, "controller is in fatal error state\n");
+ return -EIO;
+ }
pci_read_config_word(pm8001_ha->pdev, PCI_DEVICE_ID, &deviceid);
pm8001_ha->nvmd_completion = &completion;
@@ -691,16 +727,23 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
payload.offset = 0;
payload.func_specific = kzalloc(payload.rd_length, GFP_KERNEL);
if (!payload.func_specific) {
- pm8001_dbg(pm8001_ha, INIT, "mem alloc fail\n");
- return;
+ pm8001_dbg(pm8001_ha, FAIL, "mem alloc fail\n");
+ return -ENOMEM;
}
rc = PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload);
if (rc) {
kfree(payload.func_specific);
- pm8001_dbg(pm8001_ha, INIT, "nvmd failed\n");
- return;
+ pm8001_dbg(pm8001_ha, FAIL, "nvmd failed\n");
+ return -EIO;
+ }
+ time_remaining = wait_for_completion_timeout(&completion,
+ secs_to_jiffies(60)); // 1 min
+ if (!time_remaining) {
+ kfree(payload.func_specific);
+ pm8001_dbg(pm8001_ha, FAIL, "get_nvmd_req timeout\n");
+ return -EIO;
}
- wait_for_completion(&completion);
+
for (i = 0, j = 0; i <= 7; i++, j++) {
if (pm8001_ha->chip_id == chip_8001) {
@@ -729,16 +772,8 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
pm8001_ha->phy[i].dev_sas_addr);
}
kfree(payload.func_specific);
-#else
- for (i = 0; i < pm8001_ha->chip->n_phy; i++) {
- pm8001_ha->phy[i].dev_sas_addr = 0x50010c600047f9d0ULL;
- pm8001_ha->phy[i].dev_sas_addr =
- cpu_to_be64((u64)
- (*(u64 *)&pm8001_ha->phy[i].dev_sas_addr));
- }
- memcpy(pm8001_ha->sas_addr, &pm8001_ha->phy[0].dev_sas_addr,
- SAS_ADDR_SIZE);
-#endif
+
+ return 0;
}
/*
@@ -747,13 +782,13 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
*/
static int pm8001_get_phy_settings_info(struct pm8001_hba_info *pm8001_ha)
{
-
-#ifdef PM8001_READ_VPD
- /*OPTION ROM FLASH read for the SPC cards */
DECLARE_COMPLETION_ONSTACK(completion);
struct pm8001_ioctl_payload payload;
int rc;
+ if (!pm8001_read_wwn)
+ return 0;
+
pm8001_ha->nvmd_completion = &completion;
/* SAS ADDRESS read from flash / EEPROM */
payload.minor_function = 6;
@@ -772,7 +807,7 @@ static int pm8001_get_phy_settings_info(struct pm8001_hba_info *pm8001_ha)
wait_for_completion(&completion);
pm8001_set_phy_profile(pm8001_ha, sizeof(u8), payload.func_specific);
kfree(payload.func_specific);
-#endif
+
return 0;
}
@@ -923,38 +958,41 @@ static int pm8001_configure_phy_settings(struct pm8001_hba_info *pm8001_ha)
}
}
-#ifdef PM8001_USE_MSIX
/**
* pm8001_setup_msix - enable MSI-X interrupt
* @pm8001_ha: our ha struct.
*/
static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha)
{
- u32 number_of_intr;
- int rc, cpu_online_count;
unsigned int allocated_irq_vectors;
+ int rc;
/* SPCv controllers supports 64 msi-x */
if (pm8001_ha->chip_id == chip_8001) {
- number_of_intr = 1;
+ rc = pci_alloc_irq_vectors(pm8001_ha->pdev, 1, 1,
+ PCI_IRQ_MSIX);
} else {
- number_of_intr = PM8001_MAX_MSIX_VEC;
+ /*
+ * Queue index #0 is used always for housekeeping, so don't
+ * include in the affinity spreading.
+ */
+ struct irq_affinity desc = {
+ .pre_vectors = 1,
+ };
+ rc = pci_alloc_irq_vectors_affinity(
+ pm8001_ha->pdev, 2, PM8001_MAX_MSIX_VEC,
+ PCI_IRQ_MSIX | PCI_IRQ_AFFINITY, &desc);
}
- cpu_online_count = num_online_cpus();
- number_of_intr = min_t(int, cpu_online_count, number_of_intr);
- rc = pci_alloc_irq_vectors(pm8001_ha->pdev, number_of_intr,
- number_of_intr, PCI_IRQ_MSIX);
allocated_irq_vectors = rc;
if (rc < 0)
return rc;
/* Assigns the number of interrupts */
- number_of_intr = min_t(int, allocated_irq_vectors, number_of_intr);
- pm8001_ha->number_of_intr = number_of_intr;
+ pm8001_ha->number_of_intr = allocated_irq_vectors;
/* Maximum queue number updating in HBA structure */
- pm8001_ha->max_q_num = number_of_intr;
+ pm8001_ha->max_q_num = allocated_irq_vectors;
pm8001_dbg(pm8001_ha, INIT,
"pci_alloc_irq_vectors request ret:%d no of intr %d\n",
@@ -1001,21 +1039,6 @@ static u32 pm8001_request_msix(struct pm8001_hba_info *pm8001_ha)
return rc;
}
-#endif
-
-static u32 pm8001_setup_irq(struct pm8001_hba_info *pm8001_ha)
-{
- struct pci_dev *pdev;
-
- pdev = pm8001_ha->pdev;
-
-#ifdef PM8001_USE_MSIX
- if (pci_find_capability(pdev, PCI_CAP_ID_MSIX))
- return pm8001_setup_msix(pm8001_ha);
- pm8001_dbg(pm8001_ha, INIT, "MSIX not supported!!!\n");
-#endif
- return 0;
-}
/**
* pm8001_request_irq - register interrupt
@@ -1023,27 +1046,59 @@ static u32 pm8001_setup_irq(struct pm8001_hba_info *pm8001_ha)
*/
static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha)
{
- struct pci_dev *pdev;
+ struct pci_dev *pdev = pm8001_ha->pdev;
int rc;
- pdev = pm8001_ha->pdev;
+ if (pm8001_use_msix && pci_find_capability(pdev, PCI_CAP_ID_MSIX)) {
+ rc = pm8001_setup_msix(pm8001_ha);
+ if (rc) {
+ pm8001_dbg(pm8001_ha, FAIL,
+ "pm8001_setup_irq failed [ret: %d]\n", rc);
+ return rc;
+ }
-#ifdef PM8001_USE_MSIX
- if (pdev->msix_cap && pci_msi_enabled())
- return pm8001_request_msix(pm8001_ha);
- else {
- pm8001_dbg(pm8001_ha, INIT, "MSIX not supported!!!\n");
- goto intx;
+ if (!pdev->msix_cap || !pci_msi_enabled())
+ goto use_intx;
+
+ rc = pm8001_request_msix(pm8001_ha);
+ if (rc)
+ return rc;
+
+ pm8001_ha->use_msix = true;
+
+ return 0;
}
-#endif
-intx:
- /* initialize the INT-X interrupt */
+use_intx:
+ /* Initialize the INT-X interrupt */
+ pm8001_dbg(pm8001_ha, INIT, "MSIX not supported!!!\n");
+ pm8001_ha->use_msix = false;
pm8001_ha->irq_vector[0].irq_id = 0;
pm8001_ha->irq_vector[0].drv_inst = pm8001_ha;
- rc = request_irq(pdev->irq, pm8001_interrupt_handler_intx, IRQF_SHARED,
- pm8001_ha->name, SHOST_TO_SAS_HA(pm8001_ha->shost));
- return rc;
+
+ return request_irq(pdev->irq, pm8001_interrupt_handler_intx,
+ IRQF_SHARED, pm8001_ha->name,
+ SHOST_TO_SAS_HA(pm8001_ha->shost));
+}
+
+static void pm8001_free_irq(struct pm8001_hba_info *pm8001_ha)
+{
+ struct pci_dev *pdev = pm8001_ha->pdev;
+ int i;
+
+ if (pm8001_ha->use_msix) {
+ for (i = 0; i < pm8001_ha->number_of_intr; i++)
+ synchronize_irq(pci_irq_vector(pdev, i));
+
+ for (i = 0; i < pm8001_ha->number_of_intr; i++)
+ free_irq(pci_irq_vector(pdev, i), &pm8001_ha->irq_vector[i]);
+
+ pci_free_irq_vectors(pdev);
+ return;
+ }
+
+ /* INT-X */
+ free_irq(pm8001_ha->irq, pm8001_ha->sas);
}
/**
@@ -1121,10 +1176,23 @@ static int pm8001_pci_probe(struct pci_dev *pdev,
goto err_out_ha_free;
}
- rc = pm8001_init_ccb_tag(pm8001_ha, shost, pdev);
+ rc = pm8001_init_ccb_tag(pm8001_ha);
if (rc)
goto err_out_enable;
+
+ PM8001_CHIP_DISP->chip_post_init(pm8001_ha);
+
+ if (pm8001_ha->number_of_intr > 1) {
+ shost->nr_hw_queues = pm8001_ha->number_of_intr - 1;
+ /*
+ * For now, ensure we're not sent too many commands by setting
+ * host_tagset. This is also required if we start using request
+ * tag.
+ */
+ shost->host_tagset = 1;
+ }
+
rc = scsi_add_host(shost, &pdev->dev);
if (rc)
goto err_out_ha_free;
@@ -1137,7 +1205,9 @@ static int pm8001_pci_probe(struct pci_dev *pdev,
pm80xx_set_thermal_config(pm8001_ha);
}
- pm8001_init_sas_add(pm8001_ha);
+ rc = pm8001_init_sas_add(pm8001_ha);
+ if (rc)
+ goto err_out_shost;
/* phy setting support for motherboard controller */
rc = pm8001_configure_phy_settings(pm8001_ha);
if (rc)
@@ -1174,26 +1244,21 @@ err_out_enable:
/**
* pm8001_init_ccb_tag - allocate memory to CCB and tag.
* @pm8001_ha: our hba card information.
- * @shost: scsi host which has been allocated outside.
- * @pdev: pci device.
*/
-static int
-pm8001_init_ccb_tag(struct pm8001_hba_info *pm8001_ha, struct Scsi_Host *shost,
- struct pci_dev *pdev)
+static int pm8001_init_ccb_tag(struct pm8001_hba_info *pm8001_ha)
{
- int i = 0;
+ struct Scsi_Host *shost = pm8001_ha->shost;
+ struct device *dev = pm8001_ha->dev;
u32 max_out_io, ccb_count;
- u32 can_queue;
+ int i;
max_out_io = pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_out_io;
ccb_count = min_t(int, PM8001_MAX_CCB, max_out_io);
- /* Update to the scsi host*/
- can_queue = ccb_count - PM8001_RESERVE_SLOT;
- shost->can_queue = can_queue;
+ shost->can_queue = ccb_count - PM8001_RESERVE_SLOT;
- pm8001_ha->tags = bitmap_zalloc(ccb_count, GFP_KERNEL);
- if (!pm8001_ha->tags)
+ pm8001_ha->rsvd_tags = bitmap_zalloc(PM8001_RESERVE_SLOT, GFP_KERNEL);
+ if (!pm8001_ha->rsvd_tags)
goto err_out;
/* Memory region for ccb_info*/
@@ -1206,7 +1271,7 @@ pm8001_init_ccb_tag(struct pm8001_hba_info *pm8001_ha, struct Scsi_Host *shost,
goto err_out_noccb;
}
for (i = 0; i < ccb_count; i++) {
- pm8001_ha->ccb_info[i].buf_prd = dma_alloc_coherent(&pdev->dev,
+ pm8001_ha->ccb_info[i].buf_prd = dma_alloc_coherent(dev,
sizeof(struct pm8001_prd) * PM8001_MAX_DMA_SG,
&pm8001_ha->ccb_info[i].ccb_dma_handle,
GFP_KERNEL);
@@ -1216,10 +1281,10 @@ pm8001_init_ccb_tag(struct pm8001_hba_info *pm8001_ha, struct Scsi_Host *shost,
goto err_out;
}
pm8001_ha->ccb_info[i].task = NULL;
- pm8001_ha->ccb_info[i].ccb_tag = 0xffffffff;
+ pm8001_ha->ccb_info[i].ccb_tag = PM8001_INVALID_TAG;
pm8001_ha->ccb_info[i].device = NULL;
- ++pm8001_ha->tags_num;
}
+
return 0;
err_out_noccb:
@@ -1231,33 +1296,17 @@ err_out:
static void pm8001_pci_remove(struct pci_dev *pdev)
{
struct sas_ha_struct *sha = pci_get_drvdata(pdev);
- struct pm8001_hba_info *pm8001_ha;
- int i, j;
- pm8001_ha = sha->lldd_ha;
+ struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
+ int i;
+
sas_unregister_ha(sha);
sas_remove_host(pm8001_ha->shost);
list_del(&pm8001_ha->list);
PM8001_CHIP_DISP->interrupt_disable(pm8001_ha, 0xFF);
PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha);
-#ifdef PM8001_USE_MSIX
- for (i = 0; i < pm8001_ha->number_of_intr; i++)
- synchronize_irq(pci_irq_vector(pdev, i));
- for (i = 0; i < pm8001_ha->number_of_intr; i++)
- free_irq(pci_irq_vector(pdev, i), &pm8001_ha->irq_vector[i]);
- pci_free_irq_vectors(pdev);
-#else
- free_irq(pm8001_ha->irq, sha);
-#endif
-#ifdef PM8001_USE_TASKLET
- /* For non-msix and msix interrupts */
- if ((!pdev->msix_cap || !pci_msi_enabled()) ||
- (pm8001_ha->chip_id == chip_8001))
- tasklet_kill(&pm8001_ha->tasklet[0]);
- else
- for (j = 0; j < PM8001_MAX_MSIX_VEC; j++)
- tasklet_kill(&pm8001_ha->tasklet[j]);
-#endif
+ pm8001_free_irq(pm8001_ha);
+ pm8001_kill_tasklet(pm8001_ha);
scsi_host_put(pm8001_ha->shost);
for (i = 0; i < pm8001_ha->ccb_count; i++) {
@@ -1288,7 +1337,7 @@ static int __maybe_unused pm8001_pci_suspend(struct device *dev)
struct pci_dev *pdev = to_pci_dev(dev);
struct sas_ha_struct *sha = pci_get_drvdata(pdev);
struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
- int i, j;
+
sas_suspend_ha(sha);
flush_workqueue(pm8001_wq);
scsi_block_requests(pm8001_ha->shost);
@@ -1298,24 +1347,10 @@ static int __maybe_unused pm8001_pci_suspend(struct device *dev)
}
PM8001_CHIP_DISP->interrupt_disable(pm8001_ha, 0xFF);
PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha);
-#ifdef PM8001_USE_MSIX
- for (i = 0; i < pm8001_ha->number_of_intr; i++)
- synchronize_irq(pci_irq_vector(pdev, i));
- for (i = 0; i < pm8001_ha->number_of_intr; i++)
- free_irq(pci_irq_vector(pdev, i), &pm8001_ha->irq_vector[i]);
- pci_free_irq_vectors(pdev);
-#else
- free_irq(pm8001_ha->irq, sha);
-#endif
-#ifdef PM8001_USE_TASKLET
- /* For non-msix and msix interrupts */
- if ((!pdev->msix_cap || !pci_msi_enabled()) ||
- (pm8001_ha->chip_id == chip_8001))
- tasklet_kill(&pm8001_ha->tasklet[0]);
- else
- for (j = 0; j < PM8001_MAX_MSIX_VEC; j++)
- tasklet_kill(&pm8001_ha->tasklet[j]);
-#endif
+
+ pm8001_free_irq(pm8001_ha);
+ pm8001_kill_tasklet(pm8001_ha);
+
pm8001_info(pm8001_ha, "pdev=0x%p, slot=%s, entering "
"suspended state\n", pdev,
pm8001_ha->name);
@@ -1334,14 +1369,14 @@ static int __maybe_unused pm8001_pci_resume(struct device *dev)
struct sas_ha_struct *sha = pci_get_drvdata(pdev);
struct pm8001_hba_info *pm8001_ha;
int rc;
- u8 i = 0, j;
- u32 device_state;
+ u8 i = 0;
DECLARE_COMPLETION_ONSTACK(completion);
+
pm8001_ha = sha->lldd_ha;
- device_state = pdev->current_state;
- pm8001_info(pm8001_ha, "pdev=0x%p, slot=%s, resuming from previous operating state [D%d]\n",
- pdev, pm8001_ha->name, device_state);
+ pm8001_info(pm8001_ha,
+ "pdev=0x%p, slot=%s, resuming from previous operating state [D%d]\n",
+ pdev, pm8001_ha->name, pdev->current_state);
rc = pci_go_44(pdev);
if (rc)
@@ -1362,17 +1397,9 @@ static int __maybe_unused pm8001_pci_resume(struct device *dev)
rc = pm8001_request_irq(pm8001_ha);
if (rc)
goto err_out_disable;
-#ifdef PM8001_USE_TASKLET
- /* Tasklet for non msi-x interrupt handler */
- if ((!pdev->msix_cap || !pci_msi_enabled()) ||
- (pm8001_ha->chip_id == chip_8001))
- tasklet_init(&pm8001_ha->tasklet[0], pm8001_tasklet,
- (unsigned long)&(pm8001_ha->irq_vector[0]));
- else
- for (j = 0; j < PM8001_MAX_MSIX_VEC; j++)
- tasklet_init(&pm8001_ha->tasklet[j], pm8001_tasklet,
- (unsigned long)&(pm8001_ha->irq_vector[j]));
-#endif
+
+ pm8001_init_tasklet(pm8001_ha);
+
PM8001_CHIP_DISP->interrupt_enable(pm8001_ha, 0);
if (pm8001_ha->chip_id != chip_8001) {
for (i = 1; i < pm8001_ha->number_of_intr; i++)
@@ -1409,7 +1436,7 @@ err_out_disable:
/* update of pci device, vendor id and driver data with
* unique value for each of the controller
*/
-static struct pci_device_id pm8001_pci_table[] = {
+static const struct pci_device_id pm8001_pci_table[] = {
{ PCI_VDEVICE(PMC_Sierra, 0x8001), chip_8001 },
{ PCI_VDEVICE(PMC_Sierra, 0x8006), chip_8006 },
{ PCI_VDEVICE(ADAPTEC2, 0x8006), chip_8006 },
@@ -1504,7 +1531,10 @@ static int __init pm8001_init(void)
{
int rc = -ENOMEM;
- pm8001_wq = alloc_workqueue("pm80xx", 0, 0);
+ if (pm8001_use_tasklet && !pm8001_use_msix)
+ pm8001_use_tasklet = false;
+
+ pm8001_wq = alloc_workqueue("pm80xx", WQ_PERCPU, 0);
if (!pm8001_wq)
goto err;