diff options
Diffstat (limited to 'drivers/scsi/pm8001/pm8001_init.c')
-rw-r--r-- | drivers/scsi/pm8001/pm8001_init.c | 567 |
1 files changed, 364 insertions, 203 deletions
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index 3c6076e4c6d2..7a7d63aa90e2 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -56,8 +56,9 @@ MODULE_PARM_DESC(link_rate, "Enable link rate.\n" " 8: Link rate 12.0G\n"); static struct scsi_transport_template *pm8001_stt; +static int pm8001_init_ccb_tag(struct pm8001_hba_info *); -/** +/* * chip info structure to identify chip key functionality as * encryption available/not, no of ports, hw specific function ref */ @@ -80,13 +81,27 @@ 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_pci_map_queues(qmap, pm8001_ha->pdev, 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, + .proc_name = DRV_NAME, .queuecommand = sas_queuecommand, + .dma_need_drain = ata_scsi_dma_need_drain, .target_alloc = sas_target_alloc, .slave_configure = sas_slave_configure, .scan_finished = pm8001_scan_finished, @@ -95,20 +110,23 @@ static struct scsi_host_template pm8001_sht = { .bios_param = sas_bios_param, .can_queue = 1, .this_id = -1, - .sg_tablesize = SG_ALL, + .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 - .shost_attrs = pm8001_host_attrs, + .shost_groups = pm8001_host_groups, .track_queue_depth = 1, + .cmd_per_lun = 32, + .map_queues = pm8001_map_queues, }; -/** +/* * Sas layer call this function to execute specific task. */ static struct sas_domain_function_template pm8001_transport_ops = { @@ -119,18 +137,20 @@ 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, }; /** - *pm8001_phy_init - initiate our adapter phys - *@pm8001_ha: our hba structure. - *@phy_id: phy id. + * pm8001_phy_init - initiate our adapter phys + * @pm8001_ha: our hba structure. + * @phy_id: phy id. */ static void pm8001_phy_init(struct pm8001_hba_info *pm8001_ha, int phy_id) { @@ -138,6 +158,8 @@ 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; @@ -154,9 +176,8 @@ static void pm8001_phy_init(struct pm8001_hba_info *pm8001_ha, int phy_id) } /** - *pm8001_free - free hba - *@pm8001_ha: our hba structure. - * + * pm8001_free - free hba + * @pm8001_ha: our hba structure. */ static void pm8001_free(struct pm8001_hba_info *pm8001_ha) { @@ -176,14 +197,14 @@ static void pm8001_free(struct pm8001_hba_info *pm8001_ha) } PM8001_CHIP_DISP->chip_iounmap(pm8001_ha); flush_workqueue(pm8001_wq); - kfree(pm8001_ha->tags); + bitmap_free(pm8001_ha->tags); kfree(pm8001_ha); } #ifdef PM8001_USE_TASKLET /** - * tasklet for 64 msi-x interrupt handler + * pm8001_tasklet() - tasklet for 64 msi-x interrupt handler * @opaque: the passed general host adapter struct * Note: pm8001_tasklet is common for pm8001 & pm80xx */ @@ -204,6 +225,7 @@ static void pm8001_tasklet(unsigned long opaque) * pm8001_interrupt_handler_msix - main MSIX interrupt handler. * It obtains the vector number and calls the equivalent bottom * half or services directly. + * @irq: interrupt number * @opaque: the passed outbound queue/vector. Host structure is * retrieved from the same. */ @@ -229,7 +251,8 @@ static irqreturn_t pm8001_interrupt_handler_msix(int irq, void *opaque) /** * pm8001_interrupt_handler_intx - main INTx interrupt handler. - * @dev_id: sas_ha structure. The HBA is retrieved from sas_has structure. + * @irq: interrupt number + * @dev_id: sas_ha structure. The HBA is retrieved from sas_ha structure. */ static irqreturn_t pm8001_interrupt_handler_intx(int irq, void *dev_id) @@ -251,20 +274,47 @@ static irqreturn_t pm8001_interrupt_handler_intx(int irq, void *dev_id) return ret; } +static u32 pm8001_setup_irq(struct pm8001_hba_info *pm8001_ha); +static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha); + /** * pm8001_alloc - initiate our hba structure and 6 DMAs area. - * @pm8001_ha:our hba structure. - * + * @pm8001_ha: our hba structure. + * @ent: PCI device ID structure to match on */ static int pm8001_alloc(struct pm8001_hba_info *pm8001_ha, const struct pci_device_id *ent) { - int i; + int i, count = 0, rc = 0; + u32 ci_offset, ib_offset, ob_offset, pi_offset; + struct inbound_queue_table *ibq; + struct outbound_queue_table *obq; + spin_lock_init(&pm8001_ha->lock); spin_lock_init(&pm8001_ha->bitmap_lock); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("pm8001_alloc: PHY:%x\n", - pm8001_ha->chip->n_phy)); + 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) + goto err_out; + + count = pm8001_ha->max_q_num; + /* Queues are chosen based on the number of cores/msix availability */ + ib_offset = pm8001_ha->ib_offset = USI_MAX_MEMCNT_BASE; + ci_offset = pm8001_ha->ci_offset = ib_offset + count; + ob_offset = pm8001_ha->ob_offset = ci_offset + count; + pi_offset = pm8001_ha->pi_offset = ob_offset + count; + pm8001_ha->max_memcnt = pi_offset + count; + for (i = 0; i < pm8001_ha->chip->n_phy; i++) { pm8001_phy_init(pm8001_ha, i); pm8001_ha->port[i].wide_port_phymap = 0; @@ -273,9 +323,6 @@ static int pm8001_alloc(struct pm8001_hba_info *pm8001_ha, INIT_LIST_HEAD(&pm8001_ha->port[i].list); } - pm8001_ha->tags = kzalloc(PM8001_MAX_CCB, GFP_KERNEL); - if (!pm8001_ha->tags) - goto err_out; /* MPI Memory region 1 for AAP Event Log for fw */ pm8001_ha->memoryMap.region[AAP1].num_elements = 1; pm8001_ha->memoryMap.region[AAP1].element_size = PM8001_EVENT_LOG_SIZE; @@ -288,54 +335,64 @@ static int pm8001_alloc(struct pm8001_hba_info *pm8001_ha, pm8001_ha->memoryMap.region[IOP].total_len = PM8001_EVENT_LOG_SIZE; pm8001_ha->memoryMap.region[IOP].alignment = 32; - for (i = 0; i < PM8001_MAX_SPCV_INB_NUM; i++) { + for (i = 0; i < count; i++) { + ibq = &pm8001_ha->inbnd_q_tbl[i]; + spin_lock_init(&ibq->iq_lock); /* MPI Memory region 3 for consumer Index of inbound queues */ - pm8001_ha->memoryMap.region[CI+i].num_elements = 1; - pm8001_ha->memoryMap.region[CI+i].element_size = 4; - pm8001_ha->memoryMap.region[CI+i].total_len = 4; - pm8001_ha->memoryMap.region[CI+i].alignment = 4; + pm8001_ha->memoryMap.region[ci_offset+i].num_elements = 1; + pm8001_ha->memoryMap.region[ci_offset+i].element_size = 4; + pm8001_ha->memoryMap.region[ci_offset+i].total_len = 4; + pm8001_ha->memoryMap.region[ci_offset+i].alignment = 4; if ((ent->driver_data) != chip_8001) { /* MPI Memory region 5 inbound queues */ - pm8001_ha->memoryMap.region[IB+i].num_elements = + pm8001_ha->memoryMap.region[ib_offset+i].num_elements = PM8001_MPI_QUEUE; - pm8001_ha->memoryMap.region[IB+i].element_size = 128; - pm8001_ha->memoryMap.region[IB+i].total_len = + pm8001_ha->memoryMap.region[ib_offset+i].element_size + = 128; + pm8001_ha->memoryMap.region[ib_offset+i].total_len = PM8001_MPI_QUEUE * 128; - pm8001_ha->memoryMap.region[IB+i].alignment = 128; + pm8001_ha->memoryMap.region[ib_offset+i].alignment + = 128; } else { - pm8001_ha->memoryMap.region[IB+i].num_elements = + pm8001_ha->memoryMap.region[ib_offset+i].num_elements = PM8001_MPI_QUEUE; - pm8001_ha->memoryMap.region[IB+i].element_size = 64; - pm8001_ha->memoryMap.region[IB+i].total_len = + pm8001_ha->memoryMap.region[ib_offset+i].element_size + = 64; + pm8001_ha->memoryMap.region[ib_offset+i].total_len = PM8001_MPI_QUEUE * 64; - pm8001_ha->memoryMap.region[IB+i].alignment = 64; + pm8001_ha->memoryMap.region[ib_offset+i].alignment = 64; } } - for (i = 0; i < PM8001_MAX_SPCV_OUTB_NUM; i++) { + for (i = 0; i < count; i++) { + obq = &pm8001_ha->outbnd_q_tbl[i]; + spin_lock_init(&obq->oq_lock); /* MPI Memory region 4 for producer Index of outbound queues */ - pm8001_ha->memoryMap.region[PI+i].num_elements = 1; - pm8001_ha->memoryMap.region[PI+i].element_size = 4; - pm8001_ha->memoryMap.region[PI+i].total_len = 4; - pm8001_ha->memoryMap.region[PI+i].alignment = 4; + pm8001_ha->memoryMap.region[pi_offset+i].num_elements = 1; + pm8001_ha->memoryMap.region[pi_offset+i].element_size = 4; + pm8001_ha->memoryMap.region[pi_offset+i].total_len = 4; + pm8001_ha->memoryMap.region[pi_offset+i].alignment = 4; if (ent->driver_data != chip_8001) { /* MPI Memory region 6 Outbound queues */ - pm8001_ha->memoryMap.region[OB+i].num_elements = + pm8001_ha->memoryMap.region[ob_offset+i].num_elements = PM8001_MPI_QUEUE; - pm8001_ha->memoryMap.region[OB+i].element_size = 128; - pm8001_ha->memoryMap.region[OB+i].total_len = + pm8001_ha->memoryMap.region[ob_offset+i].element_size + = 128; + pm8001_ha->memoryMap.region[ob_offset+i].total_len = PM8001_MPI_QUEUE * 128; - pm8001_ha->memoryMap.region[OB+i].alignment = 128; + pm8001_ha->memoryMap.region[ob_offset+i].alignment + = 128; } else { /* MPI Memory region 6 Outbound queues */ - pm8001_ha->memoryMap.region[OB+i].num_elements = + pm8001_ha->memoryMap.region[ob_offset+i].num_elements = PM8001_MPI_QUEUE; - pm8001_ha->memoryMap.region[OB+i].element_size = 64; - pm8001_ha->memoryMap.region[OB+i].total_len = + pm8001_ha->memoryMap.region[ob_offset+i].element_size + = 64; + pm8001_ha->memoryMap.region[ob_offset+i].total_len = PM8001_MPI_QUEUE * 64; - pm8001_ha->memoryMap.region[OB+i].alignment = 64; + pm8001_ha->memoryMap.region[ob_offset+i].alignment = 64; } } @@ -343,19 +400,6 @@ static int pm8001_alloc(struct pm8001_hba_info *pm8001_ha, pm8001_ha->memoryMap.region[NVMD].num_elements = 1; pm8001_ha->memoryMap.region[NVMD].element_size = 4096; pm8001_ha->memoryMap.region[NVMD].total_len = 4096; - /* Memory region for devices*/ - pm8001_ha->memoryMap.region[DEV_MEM].num_elements = 1; - pm8001_ha->memoryMap.region[DEV_MEM].element_size = PM8001_MAX_DEVICES * - sizeof(struct pm8001_device); - pm8001_ha->memoryMap.region[DEV_MEM].total_len = PM8001_MAX_DEVICES * - sizeof(struct pm8001_device); - - /* Memory region for ccb_info*/ - pm8001_ha->memoryMap.region[CCB_MEM].num_elements = 1; - pm8001_ha->memoryMap.region[CCB_MEM].element_size = PM8001_MAX_CCB * - sizeof(struct pm8001_ccb_info); - pm8001_ha->memoryMap.region[CCB_MEM].total_len = PM8001_MAX_CCB * - sizeof(struct pm8001_ccb_info); /* Memory region for fw flash */ pm8001_ha->memoryMap.region[FW_FLASH].total_len = 4096; @@ -364,50 +408,57 @@ static int pm8001_alloc(struct pm8001_hba_info *pm8001_ha, pm8001_ha->memoryMap.region[FORENSIC_MEM].total_len = 0x10000; pm8001_ha->memoryMap.region[FORENSIC_MEM].element_size = 0x10000; pm8001_ha->memoryMap.region[FORENSIC_MEM].alignment = 0x10000; - for (i = 0; i < USI_MAX_MEMCNT; i++) { + for (i = 0; i < pm8001_ha->max_memcnt; i++) { + struct mpi_mem *region = &pm8001_ha->memoryMap.region[i]; + if (pm8001_mem_alloc(pm8001_ha->pdev, - &pm8001_ha->memoryMap.region[i].virt_ptr, - &pm8001_ha->memoryMap.region[i].phys_addr, - &pm8001_ha->memoryMap.region[i].phys_addr_hi, - &pm8001_ha->memoryMap.region[i].phys_addr_lo, - pm8001_ha->memoryMap.region[i].total_len, - pm8001_ha->memoryMap.region[i].alignment) != 0) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Mem%d alloc failed\n", - i)); - goto err_out; + ®ion->virt_ptr, + ®ion->phys_addr, + ®ion->phys_addr_hi, + ®ion->phys_addr_lo, + region->total_len, + region->alignment) != 0) { + pm8001_dbg(pm8001_ha, FAIL, "Mem%d alloc failed\n", i); + goto err_out; } } - pm8001_ha->devices = pm8001_ha->memoryMap.region[DEV_MEM].virt_ptr; + /* Memory region for devices*/ + pm8001_ha->devices = kzalloc(PM8001_MAX_DEVICES + * sizeof(struct pm8001_device), GFP_KERNEL); + if (!pm8001_ha->devices) { + rc = -ENOMEM; + goto err_out_nodev; + } 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; - pm8001_ha->devices[i].running_req = 0; - } - pm8001_ha->ccb_info = pm8001_ha->memoryMap.region[CCB_MEM].virt_ptr; - for (i = 0; i < PM8001_MAX_CCB; i++) { - pm8001_ha->ccb_info[i].ccb_dma_handle = - pm8001_ha->memoryMap.region[CCB_MEM].phys_addr + - i * sizeof(struct pm8001_ccb_info); - pm8001_ha->ccb_info[i].task = NULL; - pm8001_ha->ccb_info[i].ccb_tag = 0xffffffff; - pm8001_ha->ccb_info[i].device = NULL; - ++pm8001_ha->tags_num; + 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: + for (i = 0; i < pm8001_ha->max_memcnt; i++) { + if (pm8001_ha->memoryMap.region[i].virt_ptr != NULL) { + dma_free_coherent(&pm8001_ha->pdev->dev, + (pm8001_ha->memoryMap.region[i].total_len + + pm8001_ha->memoryMap.region[i].alignment), + pm8001_ha->memoryMap.region[i].virt_ptr, + pm8001_ha->memoryMap.region[i].phys_addr); + } + } err_out: return 1; } /** - * pm8001_ioremap - remap the pci high physical address to kernal virtual + * pm8001_ioremap - remap the pci high physical address to kernel virtual * address so that we can access them. - * @pm8001_ha:our hba structure. + * @pm8001_ha: our hba structure. */ static int pm8001_ioremap(struct pm8001_hba_info *pm8001_ha) { @@ -436,15 +487,18 @@ static int pm8001_ioremap(struct pm8001_hba_info *pm8001_ha) pm8001_ha->io_mem[logicalBar].memvirtaddr = ioremap(pm8001_ha->io_mem[logicalBar].membase, pm8001_ha->io_mem[logicalBar].memsize); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("PCI: bar %d, logicalBar %d ", - bar, logicalBar)); - PM8001_INIT_DBG(pm8001_ha, pm8001_printk( - "base addr %llx virt_addr=%llx len=%d\n", - (u64)pm8001_ha->io_mem[logicalBar].membase, - (u64)(unsigned long) - pm8001_ha->io_mem[logicalBar].memvirtaddr, - pm8001_ha->io_mem[logicalBar].memsize)); + if (!pm8001_ha->io_mem[logicalBar].memvirtaddr) { + pm8001_dbg(pm8001_ha, INIT, + "Failed to ioremap bar %d, logicalBar %d", + bar, logicalBar); + return -ENOMEM; + } + pm8001_dbg(pm8001_ha, INIT, + "base addr %llx virt_addr=%llx len=%d\n", + (u64)pm8001_ha->io_mem[logicalBar].membase, + (u64)(unsigned long) + pm8001_ha->io_mem[logicalBar].memvirtaddr, + pm8001_ha->io_mem[logicalBar].memsize); } else { pm8001_ha->io_mem[logicalBar].membase = 0; pm8001_ha->io_mem[logicalBar].memsize = 0; @@ -483,13 +537,14 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev, pm8001_ha->shost = shost; pm8001_ha->id = pm8001_id++; pm8001_ha->logging_level = logging_level; + pm8001_ha->non_fatal_count = 0; if (link_rate >= 1 && link_rate <= 15) pm8001_ha->link_rate = (link_rate << 8); else { pm8001_ha->link_rate = LINKRATE_15 | LINKRATE_30 | LINKRATE_60 | LINKRATE_120; - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( - "Setting link rate to default value\n")); + pm8001_dbg(pm8001_ha, FAIL, + "Setting link rate to default value\n"); } sprintf(pm8001_ha->name, "%s%d", DRV_NAME, pm8001_ha->id); /* IOMB size is 128 for 8088/89 controllers */ @@ -509,9 +564,11 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev, tasklet_init(&pm8001_ha->tasklet[j], pm8001_tasklet, (unsigned long)&(pm8001_ha->irq_vector[j])); #endif - pm8001_ioremap(pm8001_ha); + if (pm8001_ioremap(pm8001_ha)) + goto failed_pci_alloc; if (!pm8001_alloc(pm8001_ha, ent)) return pm8001_ha; +failed_pci_alloc: pm8001_free(pm8001_ha); return NULL; } @@ -565,12 +622,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); @@ -610,9 +663,9 @@ static void pm8001_post_sas_ha_init(struct Scsi_Host *shost, /** * pm8001_init_sas_add - initialize sas address - * @chip_info: our ha struct. + * @pm8001_ha: our ha struct. * - * Currently we just set the fixed SAS address to our HBA,for manufacture, + * 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) @@ -635,30 +688,30 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha) if (pm8001_ha->chip_id == chip_8001) { if (deviceid == 0x8081 || deviceid == 0x0042) { payload.minor_function = 4; - payload.length = 4096; + payload.rd_length = 4096; } else { payload.minor_function = 0; - payload.length = 128; + payload.rd_length = 128; } } else if ((pm8001_ha->chip_id == chip_8070 || pm8001_ha->chip_id == chip_8072) && pm8001_ha->pdev->subsystem_vendor == PCI_VENDOR_ID_ATTO) { payload.minor_function = 4; - payload.length = 4096; + payload.rd_length = 4096; } else { payload.minor_function = 1; - payload.length = 4096; + payload.rd_length = 4096; } payload.offset = 0; - payload.func_specific = kzalloc(payload.length, GFP_KERNEL); + payload.func_specific = kzalloc(payload.rd_length, GFP_KERNEL); if (!payload.func_specific) { - PM8001_INIT_DBG(pm8001_ha, pm8001_printk("mem alloc fail\n")); + pm8001_dbg(pm8001_ha, INIT, "mem alloc fail\n"); return; } rc = PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload); if (rc) { kfree(payload.func_specific); - PM8001_INIT_DBG(pm8001_ha, pm8001_printk("nvmd failed\n")); + pm8001_dbg(pm8001_ha, INIT, "nvmd failed\n"); return; } wait_for_completion(&completion); @@ -686,9 +739,8 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha) sas_add[7] = sas_add[7] + 4; memcpy(&pm8001_ha->phy[i].dev_sas_addr, sas_add, SAS_ADDR_SIZE); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("phy %d sas_addr = %016llx\n", i, - pm8001_ha->phy[i].dev_sas_addr)); + pm8001_dbg(pm8001_ha, INIT, "phy %d sas_addr = %016llx\n", i, + pm8001_ha->phy[i].dev_sas_addr); } kfree(payload.func_specific); #else @@ -720,7 +772,7 @@ static int pm8001_get_phy_settings_info(struct pm8001_hba_info *pm8001_ha) /* SAS ADDRESS read from flash / EEPROM */ payload.minor_function = 6; payload.offset = 0; - payload.length = 4096; + payload.rd_length = 4096; payload.func_specific = kzalloc(4096, GFP_KERNEL); if (!payload.func_specific) return -ENOMEM; @@ -728,7 +780,7 @@ static int pm8001_get_phy_settings_info(struct pm8001_hba_info *pm8001_ha) rc = PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload); if (rc) { kfree(payload.func_specific); - PM8001_INIT_DBG(pm8001_ha, pm8001_printk("nvmd failed\n")); + pm8001_dbg(pm8001_ha, INIT, "nvmd failed\n"); return -ENOMEM; } wait_for_completion(&completion); @@ -751,7 +803,7 @@ struct pm8001_mpi3_phy_pg_trx_config { }; /** - * pm8001_get_internal_phy_settings : Retrieves the internal PHY settings + * pm8001_get_internal_phy_settings - Retrieves the internal PHY settings * @pm8001_ha : our adapter * @phycfg : PHY config page to populate */ @@ -771,7 +823,7 @@ void pm8001_get_internal_phy_settings(struct pm8001_hba_info *pm8001_ha, } /** - * pm8001_get_external_phy_settings : Retrieves the external PHY settings + * pm8001_get_external_phy_settings - Retrieves the external PHY settings * @pm8001_ha : our adapter * @phycfg : PHY config page to populate */ @@ -791,7 +843,7 @@ void pm8001_get_external_phy_settings(struct pm8001_hba_info *pm8001_ha, } /** - * pm8001_get_phy_mask : Retrieves the mask that denotes if a PHY is int/ext + * pm8001_get_phy_mask - Retrieves the mask that denotes if a PHY is int/ext * @pm8001_ha : our adapter * @phymask : The PHY mask */ @@ -822,14 +874,14 @@ void pm8001_get_phy_mask(struct pm8001_hba_info *pm8001_ha, int *phymask) break; default: - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("Unknown subsystem device=0x%.04x", - pm8001_ha->pdev->subsystem_device)); + pm8001_dbg(pm8001_ha, INIT, + "Unknown subsystem device=0x%.04x\n", + pm8001_ha->pdev->subsystem_device); } } /** - * pm8001_set_phy_settings_ven_117c_12Gb : Configure ATTO 12Gb PHY settings + * pm8001_set_phy_settings_ven_117c_12G() - Configure ATTO 12Gb PHY settings * @pm8001_ha : our adapter */ static @@ -864,7 +916,7 @@ int pm8001_set_phy_settings_ven_117c_12G(struct pm8001_hba_info *pm8001_ha) } /** - * pm8001_configure_phy_settings : Configures PHY settings based on vendor ID. + * pm8001_configure_phy_settings - Configures PHY settings based on vendor ID. * @pm8001_ha : our hba. */ static int pm8001_configure_phy_settings(struct pm8001_hba_info *pm8001_ha) @@ -888,35 +940,63 @@ static int pm8001_configure_phy_settings(struct pm8001_hba_info *pm8001_ha) #ifdef PM8001_USE_MSIX /** * pm8001_setup_msix - enable MSI-X interrupt - * @chip_info: our ha struct. - * @irq_handler: irq_handler + * @pm8001_ha: our ha struct. */ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha) { - u32 i = 0, j = 0; - u32 number_of_intr; - int flag = 0; + 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; - flag &= ~IRQF_SHARED; + /* + * 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); } - 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; - pm8001_ha->number_of_intr = number_of_intr; - PM8001_INIT_DBG(pm8001_ha, pm8001_printk( - "pci_alloc_irq_vectors request ret:%d no of intr %d\n", - rc, pm8001_ha->number_of_intr)); + /* Assigns the number of interrupts */ + pm8001_ha->number_of_intr = allocated_irq_vectors; + + /* Maximum queue number updating in HBA structure */ + 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", + rc, pm8001_ha->number_of_intr); + return 0; +} - for (i = 0; i < number_of_intr; i++) { +static u32 pm8001_request_msix(struct pm8001_hba_info *pm8001_ha) +{ + u32 i = 0, j = 0; + int flag = 0, rc = 0; + int nr_irqs = pm8001_ha->number_of_intr; + + if (pm8001_ha->chip_id != chip_8001) + flag &= ~IRQF_SHARED; + + pm8001_dbg(pm8001_ha, INIT, + "pci_enable_msix request number of intr %d\n", + pm8001_ha->number_of_intr); + + if (nr_irqs > ARRAY_SIZE(pm8001_ha->intr_drvname)) + nr_irqs = ARRAY_SIZE(pm8001_ha->intr_drvname); + + for (i = 0; i < nr_irqs; i++) { snprintf(pm8001_ha->intr_drvname[i], sizeof(pm8001_ha->intr_drvname[0]), "%s-%d", pm8001_ha->name, i); @@ -941,9 +1021,23 @@ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha) } #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 - * @chip_info: our ha struct. + * @pm8001_ha: our ha struct. */ static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha) { @@ -954,10 +1048,9 @@ static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha) #ifdef PM8001_USE_MSIX if (pdev->msix_cap && pci_msi_enabled()) - return pm8001_setup_msix(pm8001_ha); + return pm8001_request_msix(pm8001_ha); else { - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("MSIX not supported!!!\n")); + pm8001_dbg(pm8001_ha, INIT, "MSIX not supported!!!\n"); goto intx; } #endif @@ -977,8 +1070,8 @@ intx: * @ent: pci device id * * This function is the main initialization function, when register a new - * pci driver it is invoked, all struct an hardware initilization should be done - * here, also, register interrupt + * pci driver it is invoked, all struct and hardware initialization should be + * done here, also, register interrupt. */ static int pm8001_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -989,6 +1082,7 @@ static int pm8001_pci_probe(struct pci_dev *pdev, struct pm8001_hba_info *pm8001_ha; struct Scsi_Host *shost = NULL; const struct pm8001_chip_info *chip; + struct sas_ha_struct *sha; dev_printk(KERN_INFO, &pdev->dev, "pm80xx: driver version %s\n", DRV_VERSION); @@ -1017,12 +1111,12 @@ static int pm8001_pci_probe(struct pci_dev *pdev, goto err_out_regions; } chip = &pm8001_chips[ent->driver_data]; - SHOST_TO_SAS_HA(shost) = - kzalloc(sizeof(struct sas_ha_struct), GFP_KERNEL); - if (!SHOST_TO_SAS_HA(shost)) { + sha = kzalloc(sizeof(struct sas_ha_struct), GFP_KERNEL); + if (!sha) { rc = -ENOMEM; goto err_out_free_host; } + SHOST_TO_SAS_HA(shost) = sha; rc = pm8001_prep_sas_ha_init(shost, chip); if (rc) { @@ -1036,24 +1130,35 @@ static int pm8001_pci_probe(struct pci_dev *pdev, rc = -ENOMEM; goto err_out_free; } - list_add_tail(&pm8001_ha->list, &hba_list); + PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha); rc = PM8001_CHIP_DISP->chip_init(pm8001_ha); if (rc) { - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( - "chip_init failed [ret: %d]\n", rc)); + pm8001_dbg(pm8001_ha, FAIL, + "chip_init failed [ret: %d]\n", rc); goto err_out_ha_free; } + 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; - rc = pm8001_request_irq(pm8001_ha); - if (rc) { - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( - "pm8001_request_irq failed [ret: %d]\n", rc)); - goto err_out_shost; - } PM8001_CHIP_DISP->interrupt_enable(pm8001_ha, 0); if (pm8001_ha->chip_id != chip_8001) { @@ -1065,15 +1170,20 @@ static int pm8001_pci_probe(struct pci_dev *pdev, pm8001_init_sas_add(pm8001_ha); /* phy setting support for motherboard controller */ - if (pm8001_configure_phy_settings(pm8001_ha)) + rc = pm8001_configure_phy_settings(pm8001_ha); + if (rc) goto err_out_shost; pm8001_post_sas_ha_init(shost, chip); rc = sas_register_ha(SHOST_TO_SAS_HA(shost)); - if (rc) + if (rc) { + pm8001_dbg(pm8001_ha, FAIL, + "sas_register_ha failed [ret: %d]\n", rc); goto err_out_shost; - scsi_scan_host(pm8001_ha->shost); + } + list_add_tail(&pm8001_ha->list, &hba_list); pm8001_ha->flags = PM8001F_RUN_TIME; + scsi_scan_host(pm8001_ha->shost); return 0; err_out_shost: @@ -1081,7 +1191,7 @@ err_out_shost: err_out_ha_free: pm8001_free(pm8001_ha); err_out_free: - kfree(SHOST_TO_SAS_HA(shost)); + kfree(sha); err_out_free_host: scsi_host_put(shost); err_out_regions: @@ -1092,6 +1202,62 @@ err_out_enable: return rc; } +/** + * pm8001_init_ccb_tag - allocate memory to CCB and tag. + * @pm8001_ha: our hba card information. + */ +static int pm8001_init_ccb_tag(struct pm8001_hba_info *pm8001_ha) +{ + 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; + + pm8001_ha->tags = bitmap_zalloc(ccb_count, GFP_KERNEL); + if (!pm8001_ha->tags) + goto err_out; + + /* Memory region for ccb_info*/ + pm8001_ha->ccb_count = ccb_count; + pm8001_ha->ccb_info = + kcalloc(ccb_count, sizeof(struct pm8001_ccb_info), GFP_KERNEL); + if (!pm8001_ha->ccb_info) { + pm8001_dbg(pm8001_ha, FAIL, + "Unable to allocate memory for ccb\n"); + goto err_out_noccb; + } + for (i = 0; i < ccb_count; i++) { + 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); + if (!pm8001_ha->ccb_info[i].buf_prd) { + pm8001_dbg(pm8001_ha, FAIL, + "ccb prd memory allocation error\n"); + goto err_out; + } + pm8001_ha->ccb_info[i].task = NULL; + 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: + kfree(pm8001_ha->devices); +err_out: + return -ENOMEM; +} + static void pm8001_pci_remove(struct pci_dev *pdev) { struct sas_ha_struct *sha = pci_get_drvdata(pdev); @@ -1123,6 +1289,16 @@ static void pm8001_pci_remove(struct pci_dev *pdev) tasklet_kill(&pm8001_ha->tasklet[j]); #endif scsi_host_put(pm8001_ha->shost); + + for (i = 0; i < pm8001_ha->ccb_count; i++) { + dma_free_coherent(&pm8001_ha->pdev->dev, + sizeof(struct pm8001_prd) * PM8001_MAX_DMA_SG, + pm8001_ha->ccb_info[i].buf_prd, + pm8001_ha->ccb_info[i].ccb_dma_handle); + } + kfree(pm8001_ha->ccb_info); + kfree(pm8001_ha->devices); + pm8001_free(pm8001_ha); kfree(sha->sas_phy); kfree(sha->sas_port); @@ -1133,23 +1309,21 @@ static void pm8001_pci_remove(struct pci_dev *pdev) /** * pm8001_pci_suspend - power management suspend main entry point - * @pdev: PCI device struct - * @state: PM state change to (usually PCI_D3) + * @dev: Device struct * - * Returns 0 success, anything else error. + * Return: 0 on success, anything else on error. */ -static int pm8001_pci_suspend(struct pci_dev *pdev, pm_message_t state) +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; + struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; int i, j; - u32 device_state; - pm8001_ha = sha->lldd_ha; sas_suspend_ha(sha); flush_workqueue(pm8001_wq); scsi_block_requests(pm8001_ha->shost); if (!pdev->pm_cap) { - dev_err(&pdev->dev, " PCI PM not supported\n"); + dev_err(dev, " PCI PM not supported\n"); return -ENODEV; } PM8001_CHIP_DISP->interrupt_disable(pm8001_ha, 0xFF); @@ -1172,47 +1346,33 @@ static int pm8001_pci_suspend(struct pci_dev *pdev, pm_message_t state) for (j = 0; j < PM8001_MAX_MSIX_VEC; j++) tasklet_kill(&pm8001_ha->tasklet[j]); #endif - device_state = pci_choose_state(pdev, state); - pm8001_printk("pdev=0x%p, slot=%s, entering " - "operating state [D%d]\n", pdev, - pm8001_ha->name, device_state); - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, device_state); + pm8001_info(pm8001_ha, "pdev=0x%p, slot=%s, entering " + "suspended state\n", pdev, + pm8001_ha->name); return 0; } /** * pm8001_pci_resume - power management resume main entry point - * @pdev: PCI device struct + * @dev: Device struct * - * Returns 0 success, anything else error. + * Return: 0 on success, anything else on error. */ -static int pm8001_pci_resume(struct pci_dev *pdev) +static int __maybe_unused pm8001_pci_resume(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; int rc; u8 i = 0, j; - u32 device_state; DECLARE_COMPLETION_ONSTACK(completion); + pm8001_ha = sha->lldd_ha; - device_state = pdev->current_state; - pm8001_printk("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); - pci_set_power_state(pdev, PCI_D0); - pci_enable_wake(pdev, PCI_D0, 0); - pci_restore_state(pdev); - rc = pci_enable_device(pdev); - if (rc) { - pm8001_printk("slot=%s Enable device failed during resume\n", - pm8001_ha->name); - goto err_out_enable; - } - - pci_set_master(pdev); rc = pci_go_44(pdev); if (rc) goto err_out_disable; @@ -1220,8 +1380,7 @@ static int pm8001_pci_resume(struct pci_dev *pdev) /* chip soft rst only for spc */ if (pm8001_ha->chip_id == chip_8001) { PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("chip soft reset successful\n")); + pm8001_dbg(pm8001_ha, INIT, "chip soft reset successful\n"); } rc = PM8001_CHIP_DISP->chip_init(pm8001_ha); if (rc) @@ -1273,8 +1432,7 @@ static int pm8001_pci_resume(struct pci_dev *pdev) err_out_disable: scsi_remove_host(pm8001_ha->shost); - pci_disable_device(pdev); -err_out_enable: + return rc; } @@ -1357,13 +1515,16 @@ static struct pci_device_id pm8001_pci_table[] = { {} /* terminate list */ }; +static SIMPLE_DEV_PM_OPS(pm8001_pci_pm_ops, + pm8001_pci_suspend, + pm8001_pci_resume); + static struct pci_driver pm8001_pci_driver = { .name = DRV_NAME, .id_table = pm8001_pci_table, .probe = pm8001_pci_probe, .remove = pm8001_pci_remove, - .suspend = pm8001_pci_suspend, - .resume = pm8001_pci_resume, + .driver.pm = &pm8001_pci_pm_ops, }; /** |