|
|
|
@@ -833,25 +833,31 @@ union reply_descriptor {
|
|
|
|
|
static irqreturn_t
|
|
|
|
|
_base_interrupt(int irq, void *bus_id)
|
|
|
|
|
{
|
|
|
|
|
struct adapter_reply_queue *reply_q = bus_id;
|
|
|
|
|
union reply_descriptor rd;
|
|
|
|
|
u32 completed_cmds;
|
|
|
|
|
u8 request_desript_type;
|
|
|
|
|
u16 smid;
|
|
|
|
|
u8 cb_idx;
|
|
|
|
|
u32 reply;
|
|
|
|
|
u8 msix_index;
|
|
|
|
|
struct MPT2SAS_ADAPTER *ioc = bus_id;
|
|
|
|
|
u8 msix_index = reply_q->msix_index;
|
|
|
|
|
struct MPT2SAS_ADAPTER *ioc = reply_q->ioc;
|
|
|
|
|
Mpi2ReplyDescriptorsUnion_t *rpf;
|
|
|
|
|
u8 rc;
|
|
|
|
|
|
|
|
|
|
if (ioc->mask_interrupts)
|
|
|
|
|
return IRQ_NONE;
|
|
|
|
|
|
|
|
|
|
rpf = &ioc->reply_post_free[ioc->reply_post_host_index];
|
|
|
|
|
if (!atomic_add_unless(&reply_q->busy, 1, 1))
|
|
|
|
|
return IRQ_NONE;
|
|
|
|
|
|
|
|
|
|
rpf = &reply_q->reply_post_free[reply_q->reply_post_host_index];
|
|
|
|
|
request_desript_type = rpf->Default.ReplyFlags
|
|
|
|
|
& MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
|
|
|
|
|
if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
|
|
|
|
|
if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) {
|
|
|
|
|
atomic_dec(&reply_q->busy);
|
|
|
|
|
return IRQ_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
completed_cmds = 0;
|
|
|
|
|
cb_idx = 0xFF;
|
|
|
|
@@ -860,9 +866,7 @@ _base_interrupt(int irq, void *bus_id)
|
|
|
|
|
if (rd.u.low == UINT_MAX || rd.u.high == UINT_MAX)
|
|
|
|
|
goto out;
|
|
|
|
|
reply = 0;
|
|
|
|
|
cb_idx = 0xFF;
|
|
|
|
|
smid = le16_to_cpu(rpf->Default.DescriptorTypeDependent1);
|
|
|
|
|
msix_index = rpf->Default.MSIxIndex;
|
|
|
|
|
if (request_desript_type ==
|
|
|
|
|
MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) {
|
|
|
|
|
reply = le32_to_cpu
|
|
|
|
@@ -906,31 +910,85 @@ _base_interrupt(int irq, void *bus_id)
|
|
|
|
|
next:
|
|
|
|
|
|
|
|
|
|
rpf->Words = cpu_to_le64(ULLONG_MAX);
|
|
|
|
|
ioc->reply_post_host_index = (ioc->reply_post_host_index ==
|
|
|
|
|
reply_q->reply_post_host_index =
|
|
|
|
|
(reply_q->reply_post_host_index ==
|
|
|
|
|
(ioc->reply_post_queue_depth - 1)) ? 0 :
|
|
|
|
|
ioc->reply_post_host_index + 1;
|
|
|
|
|
reply_q->reply_post_host_index + 1;
|
|
|
|
|
request_desript_type =
|
|
|
|
|
ioc->reply_post_free[ioc->reply_post_host_index].Default.
|
|
|
|
|
ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
|
|
|
|
|
reply_q->reply_post_free[reply_q->reply_post_host_index].
|
|
|
|
|
Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
|
|
|
|
|
completed_cmds++;
|
|
|
|
|
if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
|
|
|
|
|
goto out;
|
|
|
|
|
if (!ioc->reply_post_host_index)
|
|
|
|
|
rpf = ioc->reply_post_free;
|
|
|
|
|
if (!reply_q->reply_post_host_index)
|
|
|
|
|
rpf = reply_q->reply_post_free;
|
|
|
|
|
else
|
|
|
|
|
rpf++;
|
|
|
|
|
} while (1);
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
|
|
|
|
|
if (!completed_cmds)
|
|
|
|
|
if (!completed_cmds) {
|
|
|
|
|
atomic_dec(&reply_q->busy);
|
|
|
|
|
return IRQ_NONE;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
wmb();
|
|
|
|
|
writel(ioc->reply_post_host_index, &ioc->chip->ReplyPostHostIndex);
|
|
|
|
|
if (ioc->is_warpdrive) {
|
|
|
|
|
writel(reply_q->reply_post_host_index,
|
|
|
|
|
ioc->reply_post_host_index[msix_index]);
|
|
|
|
|
atomic_dec(&reply_q->busy);
|
|
|
|
|
return IRQ_HANDLED;
|
|
|
|
|
}
|
|
|
|
|
writel(reply_q->reply_post_host_index | (msix_index <<
|
|
|
|
|
MPI2_RPHI_MSIX_INDEX_SHIFT), &ioc->chip->ReplyPostHostIndex);
|
|
|
|
|
atomic_dec(&reply_q->busy);
|
|
|
|
|
return IRQ_HANDLED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* _base_is_controller_msix_enabled - is controller support muli-reply queues
|
|
|
|
|
* @ioc: per adapter object
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
static inline int
|
|
|
|
|
_base_is_controller_msix_enabled(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
|
{
|
|
|
|
|
return (ioc->facts.IOCCapabilities &
|
|
|
|
|
MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX) && ioc->msix_enable;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* mpt2sas_base_flush_reply_queues - flushing the MSIX reply queues
|
|
|
|
|
* @ioc: per adapter object
|
|
|
|
|
* Context: ISR conext
|
|
|
|
|
*
|
|
|
|
|
* Called when a Task Management request has completed. We want
|
|
|
|
|
* to flush the other reply queues so all the outstanding IO has been
|
|
|
|
|
* completed back to OS before we process the TM completetion.
|
|
|
|
|
*
|
|
|
|
|
* Return nothing.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
mpt2sas_base_flush_reply_queues(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
|
{
|
|
|
|
|
struct adapter_reply_queue *reply_q;
|
|
|
|
|
|
|
|
|
|
/* If MSIX capability is turned off
|
|
|
|
|
* then multi-queues are not enabled
|
|
|
|
|
*/
|
|
|
|
|
if (!_base_is_controller_msix_enabled(ioc))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
|
|
|
|
|
if (ioc->shost_recovery)
|
|
|
|
|
return;
|
|
|
|
|
/* TMs are on msix_index == 0 */
|
|
|
|
|
if (reply_q->msix_index == 0)
|
|
|
|
|
continue;
|
|
|
|
|
_base_interrupt(reply_q->vector, (void *)reply_q);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* mpt2sas_base_release_callback_handler - clear interrupt callback handler
|
|
|
|
|
* @cb_idx: callback index
|
|
|
|
@@ -1080,41 +1138,6 @@ _base_config_dma_addressing(struct MPT2SAS_ADAPTER *ioc, struct pci_dev *pdev)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* _base_save_msix_table - backup msix vector table
|
|
|
|
|
* @ioc: per adapter object
|
|
|
|
|
*
|
|
|
|
|
* This address an errata where diag reset clears out the table
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
_base_save_msix_table(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (!ioc->msix_enable || ioc->msix_table_backup == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ioc->msix_vector_count; i++)
|
|
|
|
|
ioc->msix_table_backup[i] = ioc->msix_table[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* _base_restore_msix_table - this restores the msix vector table
|
|
|
|
|
* @ioc: per adapter object
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
_base_restore_msix_table(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (!ioc->msix_enable || ioc->msix_table_backup == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ioc->msix_vector_count; i++)
|
|
|
|
|
ioc->msix_table[i] = ioc->msix_table_backup[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* _base_check_enable_msix - checks MSIX capabable.
|
|
|
|
|
* @ioc: per adapter object
|
|
|
|
@@ -1127,7 +1150,7 @@ _base_check_enable_msix(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
|
{
|
|
|
|
|
int base;
|
|
|
|
|
u16 message_control;
|
|
|
|
|
u32 msix_table_offset;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX);
|
|
|
|
|
if (!base) {
|
|
|
|
@@ -1137,20 +1160,152 @@ _base_check_enable_msix(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* get msix vector count */
|
|
|
|
|
pci_read_config_word(ioc->pdev, base + 2, &message_control);
|
|
|
|
|
ioc->msix_vector_count = (message_control & 0x3FF) + 1;
|
|
|
|
|
|
|
|
|
|
/* get msix table */
|
|
|
|
|
pci_read_config_dword(ioc->pdev, base + 4, &msix_table_offset);
|
|
|
|
|
msix_table_offset &= 0xFFFFFFF8;
|
|
|
|
|
ioc->msix_table = (u32 *)((void *)ioc->chip + msix_table_offset);
|
|
|
|
|
|
|
|
|
|
/* NUMA_IO not supported for older controllers */
|
|
|
|
|
if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2004 ||
|
|
|
|
|
ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 ||
|
|
|
|
|
ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_1 ||
|
|
|
|
|
ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_2 ||
|
|
|
|
|
ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_3 ||
|
|
|
|
|
ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_1 ||
|
|
|
|
|
ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_2)
|
|
|
|
|
ioc->msix_vector_count = 1;
|
|
|
|
|
else {
|
|
|
|
|
pci_read_config_word(ioc->pdev, base + 2, &message_control);
|
|
|
|
|
ioc->msix_vector_count = (message_control & 0x3FF) + 1;
|
|
|
|
|
}
|
|
|
|
|
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "msix is supported, "
|
|
|
|
|
"vector_count(%d), table_offset(0x%08x), table(%p)\n", ioc->name,
|
|
|
|
|
ioc->msix_vector_count, msix_table_offset, ioc->msix_table));
|
|
|
|
|
"vector_count(%d)\n", ioc->name, ioc->msix_vector_count));
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* _base_free_irq - free irq
|
|
|
|
|
* @ioc: per adapter object
|
|
|
|
|
*
|
|
|
|
|
* Freeing respective reply_queue from the list.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
_base_free_irq(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
|
{
|
|
|
|
|
struct adapter_reply_queue *reply_q, *next;
|
|
|
|
|
|
|
|
|
|
if (list_empty(&ioc->reply_queue_list))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) {
|
|
|
|
|
list_del(&reply_q->list);
|
|
|
|
|
synchronize_irq(reply_q->vector);
|
|
|
|
|
free_irq(reply_q->vector, reply_q);
|
|
|
|
|
kfree(reply_q);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* _base_request_irq - request irq
|
|
|
|
|
* @ioc: per adapter object
|
|
|
|
|
* @index: msix index into vector table
|
|
|
|
|
* @vector: irq vector
|
|
|
|
|
*
|
|
|
|
|
* Inserting respective reply_queue into the list.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
_base_request_irq(struct MPT2SAS_ADAPTER *ioc, u8 index, u32 vector)
|
|
|
|
|
{
|
|
|
|
|
struct adapter_reply_queue *reply_q;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
reply_q = kzalloc(sizeof(struct adapter_reply_queue), GFP_KERNEL);
|
|
|
|
|
if (!reply_q) {
|
|
|
|
|
printk(MPT2SAS_ERR_FMT "unable to allocate memory %d!\n",
|
|
|
|
|
ioc->name, (int)sizeof(struct adapter_reply_queue));
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
}
|
|
|
|
|
reply_q->ioc = ioc;
|
|
|
|
|
reply_q->msix_index = index;
|
|
|
|
|
reply_q->vector = vector;
|
|
|
|
|
atomic_set(&reply_q->busy, 0);
|
|
|
|
|
if (ioc->msix_enable)
|
|
|
|
|
snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d",
|
|
|
|
|
MPT2SAS_DRIVER_NAME, ioc->id, index);
|
|
|
|
|
else
|
|
|
|
|
snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d",
|
|
|
|
|
MPT2SAS_DRIVER_NAME, ioc->id);
|
|
|
|
|
r = request_irq(vector, _base_interrupt, IRQF_SHARED, reply_q->name,
|
|
|
|
|
reply_q);
|
|
|
|
|
if (r) {
|
|
|
|
|
printk(MPT2SAS_ERR_FMT "unable to allocate interrupt %d!\n",
|
|
|
|
|
reply_q->name, vector);
|
|
|
|
|
kfree(reply_q);
|
|
|
|
|
return -EBUSY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
INIT_LIST_HEAD(&reply_q->list);
|
|
|
|
|
list_add_tail(&reply_q->list, &ioc->reply_queue_list);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* _base_assign_reply_queues - assigning msix index for each cpu
|
|
|
|
|
* @ioc: per adapter object
|
|
|
|
|
*
|
|
|
|
|
* The enduser would need to set the affinity via /proc/irq/#/smp_affinity
|
|
|
|
|
*
|
|
|
|
|
* It would nice if we could call irq_set_affinity, however it is not
|
|
|
|
|
* an exported symbol
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
_base_assign_reply_queues(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
|
{
|
|
|
|
|
struct adapter_reply_queue *reply_q;
|
|
|
|
|
int cpu_id;
|
|
|
|
|
int cpu_grouping, loop, grouping, grouping_mod;
|
|
|
|
|
|
|
|
|
|
if (!_base_is_controller_msix_enabled(ioc))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
memset(ioc->cpu_msix_table, 0, ioc->cpu_msix_table_sz);
|
|
|
|
|
/* when there are more cpus than available msix vectors,
|
|
|
|
|
* then group cpus togeather on same irq
|
|
|
|
|
*/
|
|
|
|
|
if (ioc->cpu_count > ioc->msix_vector_count) {
|
|
|
|
|
grouping = ioc->cpu_count / ioc->msix_vector_count;
|
|
|
|
|
grouping_mod = ioc->cpu_count % ioc->msix_vector_count;
|
|
|
|
|
if (grouping < 2 || (grouping == 2 && !grouping_mod))
|
|
|
|
|
cpu_grouping = 2;
|
|
|
|
|
else if (grouping < 4 || (grouping == 4 && !grouping_mod))
|
|
|
|
|
cpu_grouping = 4;
|
|
|
|
|
else if (grouping < 8 || (grouping == 8 && !grouping_mod))
|
|
|
|
|
cpu_grouping = 8;
|
|
|
|
|
else
|
|
|
|
|
cpu_grouping = 16;
|
|
|
|
|
} else
|
|
|
|
|
cpu_grouping = 0;
|
|
|
|
|
|
|
|
|
|
loop = 0;
|
|
|
|
|
reply_q = list_entry(ioc->reply_queue_list.next,
|
|
|
|
|
struct adapter_reply_queue, list);
|
|
|
|
|
for_each_online_cpu(cpu_id) {
|
|
|
|
|
if (!cpu_grouping) {
|
|
|
|
|
ioc->cpu_msix_table[cpu_id] = reply_q->msix_index;
|
|
|
|
|
reply_q = list_entry(reply_q->list.next,
|
|
|
|
|
struct adapter_reply_queue, list);
|
|
|
|
|
} else {
|
|
|
|
|
if (loop < cpu_grouping) {
|
|
|
|
|
ioc->cpu_msix_table[cpu_id] =
|
|
|
|
|
reply_q->msix_index;
|
|
|
|
|
loop++;
|
|
|
|
|
} else {
|
|
|
|
|
reply_q = list_entry(reply_q->list.next,
|
|
|
|
|
struct adapter_reply_queue, list);
|
|
|
|
|
ioc->cpu_msix_table[cpu_id] =
|
|
|
|
|
reply_q->msix_index;
|
|
|
|
|
loop = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* _base_disable_msix - disables msix
|
|
|
|
|
* @ioc: per adapter object
|
|
|
|
@@ -1161,8 +1316,6 @@ _base_disable_msix(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
|
{
|
|
|
|
|
if (ioc->msix_enable) {
|
|
|
|
|
pci_disable_msix(ioc->pdev);
|
|
|
|
|
kfree(ioc->msix_table_backup);
|
|
|
|
|
ioc->msix_table_backup = NULL;
|
|
|
|
|
ioc->msix_enable = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -1175,10 +1328,13 @@ _base_disable_msix(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
|
static int
|
|
|
|
|
_base_enable_msix(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
|
{
|
|
|
|
|
struct msix_entry entries;
|
|
|
|
|
struct msix_entry *entries, *a;
|
|
|
|
|
int r;
|
|
|
|
|
int i;
|
|
|
|
|
u8 try_msix = 0;
|
|
|
|
|
|
|
|
|
|
INIT_LIST_HEAD(&ioc->reply_queue_list);
|
|
|
|
|
|
|
|
|
|
if (msix_disable == -1 || msix_disable == 0)
|
|
|
|
|
try_msix = 1;
|
|
|
|
|
|
|
|
|
@@ -1188,51 +1344,48 @@ _base_enable_msix(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
|
if (_base_check_enable_msix(ioc) != 0)
|
|
|
|
|
goto try_ioapic;
|
|
|
|
|
|
|
|
|
|
ioc->msix_table_backup = kcalloc(ioc->msix_vector_count,
|
|
|
|
|
sizeof(u32), GFP_KERNEL);
|
|
|
|
|
if (!ioc->msix_table_backup) {
|
|
|
|
|
dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation for "
|
|
|
|
|
"msix_table_backup failed!!!\n", ioc->name));
|
|
|
|
|
ioc->reply_queue_count = min_t(u8, ioc->cpu_count,
|
|
|
|
|
ioc->msix_vector_count);
|
|
|
|
|
|
|
|
|
|
entries = kcalloc(ioc->reply_queue_count, sizeof(struct msix_entry),
|
|
|
|
|
GFP_KERNEL);
|
|
|
|
|
if (!entries) {
|
|
|
|
|
dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "kcalloc "
|
|
|
|
|
"failed @ at %s:%d/%s() !!!\n", ioc->name, __FILE__,
|
|
|
|
|
__LINE__, __func__));
|
|
|
|
|
goto try_ioapic;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset(&entries, 0, sizeof(struct msix_entry));
|
|
|
|
|
r = pci_enable_msix(ioc->pdev, &entries, 1);
|
|
|
|
|
for (i = 0, a = entries; i < ioc->reply_queue_count; i++, a++)
|
|
|
|
|
a->entry = i;
|
|
|
|
|
|
|
|
|
|
r = pci_enable_msix(ioc->pdev, entries, ioc->reply_queue_count);
|
|
|
|
|
if (r) {
|
|
|
|
|
dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "pci_enable_msix "
|
|
|
|
|
"failed (r=%d) !!!\n", ioc->name, r));
|
|
|
|
|
kfree(entries);
|
|
|
|
|
goto try_ioapic;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = request_irq(entries.vector, _base_interrupt, IRQF_SHARED,
|
|
|
|
|
ioc->name, ioc);
|
|
|
|
|
if (r) {
|
|
|
|
|
dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "unable to allocate "
|
|
|
|
|
"interrupt %d !!!\n", ioc->name, entries.vector));
|
|
|
|
|
pci_disable_msix(ioc->pdev);
|
|
|
|
|
goto try_ioapic;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ioc->pci_irq = entries.vector;
|
|
|
|
|
ioc->msix_enable = 1;
|
|
|
|
|
for (i = 0, a = entries; i < ioc->reply_queue_count; i++, a++) {
|
|
|
|
|
r = _base_request_irq(ioc, i, a->vector);
|
|
|
|
|
if (r) {
|
|
|
|
|
_base_free_irq(ioc);
|
|
|
|
|
_base_disable_msix(ioc);
|
|
|
|
|
kfree(entries);
|
|
|
|
|
goto try_ioapic;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
kfree(entries);
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* failback to io_apic interrupt routing */
|
|
|
|
|
try_ioapic:
|
|
|
|
|
|
|
|
|
|
r = request_irq(ioc->pdev->irq, _base_interrupt, IRQF_SHARED,
|
|
|
|
|
ioc->name, ioc);
|
|
|
|
|
if (r) {
|
|
|
|
|
printk(MPT2SAS_ERR_FMT "unable to allocate interrupt %d!\n",
|
|
|
|
|
ioc->name, ioc->pdev->irq);
|
|
|
|
|
r = -EBUSY;
|
|
|
|
|
goto out_fail;
|
|
|
|
|
}
|
|
|
|
|
r = _base_request_irq(ioc, 0, ioc->pdev->irq);
|
|
|
|
|
|
|
|
|
|
ioc->pci_irq = ioc->pdev->irq;
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
out_fail:
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1251,6 +1404,7 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
|
int i, r = 0;
|
|
|
|
|
u64 pio_chip = 0;
|
|
|
|
|
u64 chip_phys = 0;
|
|
|
|
|
struct adapter_reply_queue *reply_q;
|
|
|
|
|
|
|
|
|
|
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n",
|
|
|
|
|
ioc->name, __func__));
|
|
|
|
@@ -1313,9 +1467,11 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
|
if (r)
|
|
|
|
|
goto out_fail;
|
|
|
|
|
|
|
|
|
|
printk(MPT2SAS_INFO_FMT "%s: IRQ %d\n",
|
|
|
|
|
ioc->name, ((ioc->msix_enable) ? "PCI-MSI-X enabled" :
|
|
|
|
|
"IO-APIC enabled"), ioc->pci_irq);
|
|
|
|
|
list_for_each_entry(reply_q, &ioc->reply_queue_list, list)
|
|
|
|
|
printk(MPT2SAS_INFO_FMT "%s: IRQ %d\n",
|
|
|
|
|
reply_q->name, ((ioc->msix_enable) ? "PCI-MSI-X enabled" :
|
|
|
|
|
"IO-APIC enabled"), reply_q->vector);
|
|
|
|
|
|
|
|
|
|
printk(MPT2SAS_INFO_FMT "iomem(0x%016llx), mapped(0x%p), size(%d)\n",
|
|
|
|
|
ioc->name, (unsigned long long)chip_phys, ioc->chip, memap_sz);
|
|
|
|
|
printk(MPT2SAS_INFO_FMT "ioport(0x%016llx), size(%d)\n",
|
|
|
|
@@ -1330,7 +1486,6 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
|
if (ioc->chip_phys)
|
|
|
|
|
iounmap(ioc->chip);
|
|
|
|
|
ioc->chip_phys = 0;
|
|
|
|
|
ioc->pci_irq = -1;
|
|
|
|
|
pci_release_selected_regions(ioc->pdev, ioc->bars);
|
|
|
|
|
pci_disable_pcie_error_reporting(pdev);
|
|
|
|
|
pci_disable_device(pdev);
|
|
|
|
@@ -1577,6 +1732,12 @@ static inline void _base_writeq(__u64 b, volatile void __iomem *addr,
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static inline u8
|
|
|
|
|
_base_get_msix_index(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
|
{
|
|
|
|
|
return ioc->cpu_msix_table[smp_processor_id()];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* mpt2sas_base_put_smid_scsi_io - send SCSI_IO request to firmware
|
|
|
|
|
* @ioc: per adapter object
|
|
|
|
@@ -1593,7 +1754,7 @@ mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u16 handle)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
|
|
|
|
|
descriptor.SCSIIO.MSIxIndex = 0; /* TODO */
|
|
|
|
|
descriptor.SCSIIO.MSIxIndex = _base_get_msix_index(ioc);
|
|
|
|
|
descriptor.SCSIIO.SMID = cpu_to_le16(smid);
|
|
|
|
|
descriptor.SCSIIO.DevHandle = cpu_to_le16(handle);
|
|
|
|
|
descriptor.SCSIIO.LMID = 0;
|
|
|
|
@@ -1617,7 +1778,7 @@ mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid)
|
|
|
|
|
|
|
|
|
|
descriptor.HighPriority.RequestFlags =
|
|
|
|
|
MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
|
|
|
|
|
descriptor.HighPriority.MSIxIndex = 0; /* TODO */
|
|
|
|
|
descriptor.HighPriority.MSIxIndex = 0;
|
|
|
|
|
descriptor.HighPriority.SMID = cpu_to_le16(smid);
|
|
|
|
|
descriptor.HighPriority.LMID = 0;
|
|
|
|
|
descriptor.HighPriority.Reserved1 = 0;
|
|
|
|
@@ -1639,7 +1800,7 @@ mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid)
|
|
|
|
|
u64 *request = (u64 *)&descriptor;
|
|
|
|
|
|
|
|
|
|
descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
|
|
|
|
|
descriptor.Default.MSIxIndex = 0; /* TODO */
|
|
|
|
|
descriptor.Default.MSIxIndex = _base_get_msix_index(ioc);
|
|
|
|
|
descriptor.Default.SMID = cpu_to_le16(smid);
|
|
|
|
|
descriptor.Default.LMID = 0;
|
|
|
|
|
descriptor.Default.DescriptorTypeDependent = 0;
|
|
|
|
@@ -1664,7 +1825,7 @@ mpt2sas_base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid,
|
|
|
|
|
|
|
|
|
|
descriptor.SCSITarget.RequestFlags =
|
|
|
|
|
MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET;
|
|
|
|
|
descriptor.SCSITarget.MSIxIndex = 0; /* TODO */
|
|
|
|
|
descriptor.SCSITarget.MSIxIndex = _base_get_msix_index(ioc);
|
|
|
|
|
descriptor.SCSITarget.SMID = cpu_to_le16(smid);
|
|
|
|
|
descriptor.SCSITarget.LMID = 0;
|
|
|
|
|
descriptor.SCSITarget.IoIndex = cpu_to_le16(io_index);
|
|
|
|
@@ -2171,7 +2332,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
|
|
|
|
|
u16 max_sge_elements;
|
|
|
|
|
u16 num_of_reply_frames;
|
|
|
|
|
u16 chains_needed_per_io;
|
|
|
|
|
u32 sz, total_sz;
|
|
|
|
|
u32 sz, total_sz, reply_post_free_sz;
|
|
|
|
|
u32 retry_sz;
|
|
|
|
|
u16 max_request_credit;
|
|
|
|
|
int i;
|
|
|
|
@@ -2498,7 +2659,12 @@ chain_done:
|
|
|
|
|
total_sz += sz;
|
|
|
|
|
|
|
|
|
|
/* reply post queue, 16 byte align */
|
|
|
|
|
sz = ioc->reply_post_queue_depth * sizeof(Mpi2DefaultReplyDescriptor_t);
|
|
|
|
|
reply_post_free_sz = ioc->reply_post_queue_depth *
|
|
|
|
|
sizeof(Mpi2DefaultReplyDescriptor_t);
|
|
|
|
|
if (_base_is_controller_msix_enabled(ioc))
|
|
|
|
|
sz = reply_post_free_sz * ioc->reply_queue_count;
|
|
|
|
|
else
|
|
|
|
|
sz = reply_post_free_sz;
|
|
|
|
|
ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool",
|
|
|
|
|
ioc->pdev, sz, 16, 0);
|
|
|
|
|
if (!ioc->reply_post_free_dma_pool) {
|
|
|
|
@@ -3186,6 +3352,7 @@ _base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
|
|
|
|
|
facts->MaxChainDepth = mpi_reply.MaxChainDepth;
|
|
|
|
|
facts->WhoInit = mpi_reply.WhoInit;
|
|
|
|
|
facts->NumberOfPorts = mpi_reply.NumberOfPorts;
|
|
|
|
|
facts->MaxMSIxVectors = mpi_reply.MaxMSIxVectors;
|
|
|
|
|
facts->RequestCredit = le16_to_cpu(mpi_reply.RequestCredit);
|
|
|
|
|
facts->MaxReplyDescriptorPostQueueDepth =
|
|
|
|
|
le16_to_cpu(mpi_reply.MaxReplyDescriptorPostQueueDepth);
|
|
|
|
@@ -3243,7 +3410,8 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
|
|
|
|
|
mpi_request.MsgVersion = cpu_to_le16(MPI2_VERSION);
|
|
|
|
|
mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (_base_is_controller_msix_enabled(ioc))
|
|
|
|
|
mpi_request.HostMSIxVectors = ioc->reply_queue_count;
|
|
|
|
|
mpi_request.SystemRequestFrameSize = cpu_to_le16(ioc->request_sz/4);
|
|
|
|
|
mpi_request.ReplyDescriptorPostQueueDepth =
|
|
|
|
|
cpu_to_le16(ioc->reply_post_queue_depth);
|
|
|
|
@@ -3512,9 +3680,6 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
|
|
|
|
|
u32 hcb_size;
|
|
|
|
|
|
|
|
|
|
printk(MPT2SAS_INFO_FMT "sending diag reset !!\n", ioc->name);
|
|
|
|
|
|
|
|
|
|
_base_save_msix_table(ioc);
|
|
|
|
|
|
|
|
|
|
drsprintk(ioc, printk(MPT2SAS_INFO_FMT "clear interrupts\n",
|
|
|
|
|
ioc->name));
|
|
|
|
|
|
|
|
|
@@ -3610,7 +3775,6 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_base_restore_msix_table(ioc);
|
|
|
|
|
printk(MPT2SAS_INFO_FMT "diag reset: SUCCESS\n", ioc->name);
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
@@ -3691,6 +3855,9 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
|
|
|
|
|
u16 smid;
|
|
|
|
|
struct _tr_list *delayed_tr, *delayed_tr_next;
|
|
|
|
|
u8 hide_flag;
|
|
|
|
|
struct adapter_reply_queue *reply_q;
|
|
|
|
|
long reply_post_free;
|
|
|
|
|
u32 reply_post_free_sz;
|
|
|
|
|
|
|
|
|
|
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
|
|
|
|
|
__func__));
|
|
|
|
@@ -3756,19 +3923,43 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
|
|
|
|
|
ioc->reply_sz)
|
|
|
|
|
ioc->reply_free[i] = cpu_to_le32(reply_address);
|
|
|
|
|
|
|
|
|
|
/* initialize reply queues */
|
|
|
|
|
_base_assign_reply_queues(ioc);
|
|
|
|
|
|
|
|
|
|
/* initialize Reply Post Free Queue */
|
|
|
|
|
for (i = 0; i < ioc->reply_post_queue_depth; i++)
|
|
|
|
|
ioc->reply_post_free[i].Words = cpu_to_le64(ULLONG_MAX);
|
|
|
|
|
reply_post_free = (long)ioc->reply_post_free;
|
|
|
|
|
reply_post_free_sz = ioc->reply_post_queue_depth *
|
|
|
|
|
sizeof(Mpi2DefaultReplyDescriptor_t);
|
|
|
|
|
list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
|
|
|
|
|
reply_q->reply_post_host_index = 0;
|
|
|
|
|
reply_q->reply_post_free = (Mpi2ReplyDescriptorsUnion_t *)
|
|
|
|
|
reply_post_free;
|
|
|
|
|
for (i = 0; i < ioc->reply_post_queue_depth; i++)
|
|
|
|
|
reply_q->reply_post_free[i].Words =
|
|
|
|
|
cpu_to_le64(ULLONG_MAX);
|
|
|
|
|
if (!_base_is_controller_msix_enabled(ioc))
|
|
|
|
|
goto skip_init_reply_post_free_queue;
|
|
|
|
|
reply_post_free += reply_post_free_sz;
|
|
|
|
|
}
|
|
|
|
|
skip_init_reply_post_free_queue:
|
|
|
|
|
|
|
|
|
|
r = _base_send_ioc_init(ioc, sleep_flag);
|
|
|
|
|
if (r)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
/* initialize the index's */
|
|
|
|
|
/* initialize reply free host index */
|
|
|
|
|
ioc->reply_free_host_index = ioc->reply_free_queue_depth - 1;
|
|
|
|
|
ioc->reply_post_host_index = 0;
|
|
|
|
|
writel(ioc->reply_free_host_index, &ioc->chip->ReplyFreeHostIndex);
|
|
|
|
|
writel(0, &ioc->chip->ReplyPostHostIndex);
|
|
|
|
|
|
|
|
|
|
/* initialize reply post host index */
|
|
|
|
|
list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
|
|
|
|
|
writel(reply_q->msix_index << MPI2_RPHI_MSIX_INDEX_SHIFT,
|
|
|
|
|
&ioc->chip->ReplyPostHostIndex);
|
|
|
|
|
if (!_base_is_controller_msix_enabled(ioc))
|
|
|
|
|
goto skip_init_reply_post_host_index;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
skip_init_reply_post_host_index:
|
|
|
|
|
|
|
|
|
|
_base_unmask_interrupts(ioc);
|
|
|
|
|
r = _base_event_notification(ioc, sleep_flag);
|
|
|
|
@@ -3819,14 +4010,10 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
|
ioc->shost_recovery = 1;
|
|
|
|
|
_base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
|
|
|
|
|
ioc->shost_recovery = 0;
|
|
|
|
|
if (ioc->pci_irq) {
|
|
|
|
|
synchronize_irq(pdev->irq);
|
|
|
|
|
free_irq(ioc->pci_irq, ioc);
|
|
|
|
|
}
|
|
|
|
|
_base_free_irq(ioc);
|
|
|
|
|
_base_disable_msix(ioc);
|
|
|
|
|
if (ioc->chip_phys)
|
|
|
|
|
iounmap(ioc->chip);
|
|
|
|
|
ioc->pci_irq = -1;
|
|
|
|
|
ioc->chip_phys = 0;
|
|
|
|
|
pci_release_selected_regions(ioc->pdev, ioc->bars);
|
|
|
|
|
pci_disable_pcie_error_reporting(pdev);
|
|
|
|
@@ -3844,14 +4031,50 @@ int
|
|
|
|
|
mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
|
{
|
|
|
|
|
int r, i;
|
|
|
|
|
int cpu_id, last_cpu_id = 0;
|
|
|
|
|
|
|
|
|
|
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
|
|
|
|
|
__func__));
|
|
|
|
|
|
|
|
|
|
/* setup cpu_msix_table */
|
|
|
|
|
ioc->cpu_count = num_online_cpus();
|
|
|
|
|
for_each_online_cpu(cpu_id)
|
|
|
|
|
last_cpu_id = cpu_id;
|
|
|
|
|
ioc->cpu_msix_table_sz = last_cpu_id + 1;
|
|
|
|
|
ioc->cpu_msix_table = kzalloc(ioc->cpu_msix_table_sz, GFP_KERNEL);
|
|
|
|
|
ioc->reply_queue_count = 1;
|
|
|
|
|
if (!ioc->cpu_msix_table) {
|
|
|
|
|
dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation for "
|
|
|
|
|
"cpu_msix_table failed!!!\n", ioc->name));
|
|
|
|
|
r = -ENOMEM;
|
|
|
|
|
goto out_free_resources;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ioc->is_warpdrive) {
|
|
|
|
|
ioc->reply_post_host_index = kcalloc(ioc->cpu_msix_table_sz,
|
|
|
|
|
sizeof(resource_size_t *), GFP_KERNEL);
|
|
|
|
|
if (!ioc->reply_post_host_index) {
|
|
|
|
|
dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation "
|
|
|
|
|
"for cpu_msix_table failed!!!\n", ioc->name));
|
|
|
|
|
r = -ENOMEM;
|
|
|
|
|
goto out_free_resources;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = mpt2sas_base_map_resources(ioc);
|
|
|
|
|
if (r)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
if (ioc->is_warpdrive) {
|
|
|
|
|
ioc->reply_post_host_index[0] =
|
|
|
|
|
(resource_size_t *)&ioc->chip->ReplyPostHostIndex;
|
|
|
|
|
|
|
|
|
|
for (i = 1; i < ioc->cpu_msix_table_sz; i++)
|
|
|
|
|
ioc->reply_post_host_index[i] = (resource_size_t *)
|
|
|
|
|
((u8 *)&ioc->chip->Doorbell + (0x4000 + ((i - 1)
|
|
|
|
|
* 4)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pci_set_drvdata(ioc->pdev, ioc->shost);
|
|
|
|
|
r = _base_get_ioc_facts(ioc, CAN_SLEEP);
|
|
|
|
|
if (r)
|
|
|
|
@@ -3972,6 +4195,9 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
|
mpt2sas_base_free_resources(ioc);
|
|
|
|
|
_base_release_memory_pools(ioc);
|
|
|
|
|
pci_set_drvdata(ioc->pdev, NULL);
|
|
|
|
|
kfree(ioc->cpu_msix_table);
|
|
|
|
|
if (ioc->is_warpdrive)
|
|
|
|
|
kfree(ioc->reply_post_host_index);
|
|
|
|
|
kfree(ioc->pd_handles);
|
|
|
|
|
kfree(ioc->tm_cmds.reply);
|
|
|
|
|
kfree(ioc->transport_cmds.reply);
|
|
|
|
@@ -4009,6 +4235,9 @@ mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
|
mpt2sas_base_free_resources(ioc);
|
|
|
|
|
_base_release_memory_pools(ioc);
|
|
|
|
|
pci_set_drvdata(ioc->pdev, NULL);
|
|
|
|
|
kfree(ioc->cpu_msix_table);
|
|
|
|
|
if (ioc->is_warpdrive)
|
|
|
|
|
kfree(ioc->reply_post_host_index);
|
|
|
|
|
kfree(ioc->pd_handles);
|
|
|
|
|
kfree(ioc->pfacts);
|
|
|
|
|
kfree(ioc->ctl_cmds.reply);
|
|
|
|
|