From: Dave Marquardt <[email protected]>
Refactor existing code for async events into a common routine,
register a channel and interrupt handler for the asynchronous
sub-queue, and set capability bits to request that VIOS use the
asynchronous sub-queue.
---
drivers/scsi/ibmvscsi/ibmvfc.c | 376 +++++++++++++++++++++++++++--------
drivers/scsi/ibmvscsi/ibmvfc.h | 3 +
drivers/scsi/ibmvscsi/ibmvfc_kunit.c | 2 +-
3 files changed, 298 insertions(+), 83 deletions(-)
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index ad1f5636e879..a2252cd2f44b 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -1514,7 +1514,8 @@ static void ibmvfc_set_login_info(struct ibmvfc_host
*vhost)
login_info->max_cmds = cpu_to_be32(max_cmds);
login_info->capabilities =
cpu_to_be64(IBMVFC_CAN_MIGRATE | IBMVFC_CAN_SEND_VF_WWPN |
- IBMVFC_CAN_USE_NOOP_CMD);
+ IBMVFC_CAN_USE_NOOP_CMD | IBMVFC_YES_SCSI |
+ IBMVFC_USE_ASYNC_SUBQ | IBMVFC_CAN_HANDLE_FPIN);
if (vhost->mq_enabled || vhost->using_channels)
login_info->capabilities |=
cpu_to_be64(IBMVFC_CAN_USE_CHANNELS);
@@ -3240,8 +3241,8 @@ static size_t ibmvfc_fpin_size_helper(u8 fpin_status)
* non-NULL - pointer to populated struct fc_els_fpin
*/
static struct fc_els_fpin *
-ibmvfc_common_fpin_to_desc(u8 fpin_status, __be64 wwpn, __be16 modifier,
- __be32 period, __be32 threshold, __be32 event_count)
+ibmvfc_common_fpin_to_desc(u8 fpin_status, __be64 wwpn, __be16 type, __be16
modifier,
+ __be32 threshold, __be32 event_count)
{
struct fc_fn_peer_congn_desc *pdesc;
struct fc_fn_congn_desc *cdesc;
@@ -3253,7 +3254,7 @@ ibmvfc_common_fpin_to_desc(u8 fpin_status, __be64 wwpn,
__be16 modifier,
if (size == 0)
return NULL;
- fpin = kzalloc(size, GFP_KERNEL);
+ fpin = kzalloc(size, GFP_ATOMIC);
if (fpin == NULL)
return NULL;
@@ -3266,12 +3267,9 @@ ibmvfc_common_fpin_to_desc(u8 fpin_status, __be64 wwpn,
__be16 modifier,
cdesc = (struct fc_fn_congn_desc *)fpin->fpin_desc;
cdesc->desc_tag = cpu_to_be32(ELS_DTAG_CONGESTION);
cdesc->desc_len =
cpu_to_be32(FC_TLV_DESC_LENGTH_FROM_SZ(*cdesc));
- if (fpin_status == IBMVFC_AE_FPIN_CONGESTION_CLEARED)
- cdesc->event_type = cpu_to_be16(FPIN_CONGN_CLEAR);
- else
- cdesc->event_type = cpu_to_be16(FPIN_CONGN_DEVICE_SPEC);
+ cdesc->event_type = type;
cdesc->event_modifier = modifier;
- cdesc->event_period = period;
+ cdesc->event_period =
cpu_to_be32(IBMVFC_FPIN_DEFAULT_EVENT_PERIOD);
cdesc->severity = FPIN_CONGN_SEVERITY_WARNING;
break;
case IBMVFC_AE_FPIN_PORT_CONGESTED:
@@ -3281,12 +3279,9 @@ ibmvfc_common_fpin_to_desc(u8 fpin_status, __be64 wwpn,
__be16 modifier,
pdesc = (struct fc_fn_peer_congn_desc *)fpin->fpin_desc;
pdesc->desc_tag = cpu_to_be32(ELS_DTAG_PEER_CONGEST);
pdesc->desc_len =
cpu_to_be32(FC_TLV_DESC_LENGTH_FROM_SZ(*pdesc));
- if (fpin_status == IBMVFC_AE_FPIN_PORT_CLEARED)
- pdesc->event_type = cpu_to_be16(FPIN_CONGN_CLEAR);
- else
- pdesc->event_type = cpu_to_be16(FPIN_CONGN_DEVICE_SPEC);
+ pdesc->event_type = type;
pdesc->event_modifier = modifier;
- pdesc->event_period = period;
+ pdesc->event_period =
cpu_to_be32(IBMVFC_FPIN_DEFAULT_EVENT_PERIOD);
pdesc->detecting_wwpn = cpu_to_be64(0);
pdesc->attached_wwpn = wwpn;
pdesc->pname_count = cpu_to_be32(1);
@@ -3297,7 +3292,7 @@ ibmvfc_common_fpin_to_desc(u8 fpin_status, __be64 wwpn,
__be16 modifier,
ldesc = (struct fc_fn_li_desc *)fpin->fpin_desc;
ldesc->desc_tag = cpu_to_be32(ELS_DTAG_LNK_INTEGRITY);
ldesc->desc_len =
cpu_to_be32(FC_TLV_DESC_LENGTH_FROM_SZ(*ldesc));
- ldesc->event_type = cpu_to_be16(FPIN_LI_UNKNOWN);
+ ldesc->event_type = type;
ldesc->event_modifier = modifier;
ldesc->event_threshold = threshold;
ldesc->event_count = event_count;
@@ -3331,9 +3326,47 @@ ibmvfc_common_fpin_to_desc(u8 fpin_status, __be64 wwpn,
__be16 modifier,
static struct fc_els_fpin *
ibmvfc_basic_fpin_to_desc(struct ibmvfc_async_crq *crq, u64 wwpn)
{
+ __be16 type;
+
+ switch (crq->fpin_status) {
+ case IBMVFC_AE_FPIN_LINK_CONGESTED:
+ case IBMVFC_AE_FPIN_PORT_CONGESTED:
+ type = cpu_to_be16(FPIN_CONGN_DEVICE_SPEC);
+ break;
+ case IBMVFC_AE_FPIN_PORT_CLEARED:
+ case IBMVFC_AE_FPIN_CONGESTION_CLEARED:
+ type = cpu_to_be16(FPIN_CONGN_CLEAR);
+ break;
+ case IBMVFC_AE_FPIN_PORT_DEGRADED:
+ type = cpu_to_be16(FPIN_LI_UNKNOWN);
+ break;
+ default:
+ return (NULL);
+ }
+
return ibmvfc_common_fpin_to_desc(crq->fpin_status, cpu_to_be64(wwpn),
- cpu_to_be16(0),
-
cpu_to_be32(IBMVFC_FPIN_DEFAULT_EVENT_PERIOD),
+ type, cpu_to_be16(0),
+
cpu_to_be32(IBMVFC_FPIN_DEFAULT_EVENT_THRESHOLD),
+ cpu_to_be32(1));
+}
+
+/**
+ * ibmvfc_full_fpin_to_desc(): allocate and populate a struct fc_els_fpin
struct
+ * containing a descriptor.
+ * @ibmvfc_fpin: Pointer to async subq FPIN data
+ *
+ * Allocate a struct fc_els_fpin containing a descriptor and populate
+ * based on data from *ibmvfc_fpin.
+ *
+ * Return:
+ * NULL - unable to allocate structure
+ * non-NULL - pointer to populated struct fc_els_fpin
+ */
+static struct fc_els_fpin *
+ibmvfc_full_fpin_to_desc(struct ibmvfc_async_subq *ibmvfc_fpin)
+{
+ return ibmvfc_common_fpin_to_desc(ibmvfc_fpin->fpin_status,
ibmvfc_fpin->wwpn,
+ cpu_to_be16(0), cpu_to_be16(0),
cpu_to_be32(IBMVFC_FPIN_DEFAULT_EVENT_THRESHOLD),
cpu_to_be32(1));
}
@@ -3344,67 +3377,99 @@ ibmvfc_basic_fpin_to_desc(struct ibmvfc_async_crq *crq,
u64 wwpn)
*/
static void ibmvfc_process_async_work(struct work_struct *work)
{
+ struct ibmvfc_async_subq_fpin *sqfpin;
+ struct ibmvfc_target *tgt, *next;
+ struct ibmvfc_async_subq *subq;
struct ibmvfc_async_work *aw;
struct ibmvfc_async_crq *crq;
- struct ibmvfc_target *tgt;
struct ibmvfc_host *vhost;
struct fc_els_fpin *fpin;
+ __be64 node_name;
+ __be64 scsi_id;
+ __be64 wwpn;
aw = container_of(work, struct ibmvfc_async_work, async_work_s);
crq = aw->crq;
+ subq = aw->subq;
vhost = aw->vhost;
- if (!crq->scsi_id && !crq->wwpn && !crq->node_name)
+ if ((!crq && !subq) || (crq && subq)) {
+ dev_err_ratelimited(vhost->dev,
+ "FPIN event received, unable to process\n");
goto end;
- list_for_each_entry(tgt, &vhost->targets, queue) {
- if (crq->scsi_id && cpu_to_be64(tgt->scsi_id) != crq->scsi_id)
+ }
+
+ if (crq) {
+ wwpn = crq->wwpn;
+ node_name = crq->node_name;
+ scsi_id = crq->scsi_id;
+ } else {
+ wwpn = subq->wwpn;
+ node_name = subq->id.node_name;
+ scsi_id = 0;
+ }
+
+ if (!scsi_id && !wwpn && !node_name)
+ goto end;
+
+ list_for_each_entry_safe(tgt, next, &vhost->targets, queue) {
+ if (scsi_id && cpu_to_be64(tgt->scsi_id) != scsi_id)
continue;
- if (crq->wwpn && cpu_to_be64(tgt->ids.port_name) != crq->wwpn)
+ if (wwpn && cpu_to_be64(tgt->ids.port_name) != wwpn)
continue;
- if (crq->node_name && cpu_to_be64(tgt->ids.node_name) !=
crq->node_name)
+ if (node_name && cpu_to_be64(tgt->ids.node_name) != node_name)
continue;
if (!tgt->rport)
continue;
- fpin = ibmvfc_basic_fpin_to_desc(crq, tgt->wwpn);
+ if (crq) {
+ fpin = ibmvfc_basic_fpin_to_desc(crq, tgt->wwpn);
+ } else {
+ sqfpin = (struct ibmvfc_async_subq_fpin *)subq;
+ fpin = ibmvfc_full_fpin_to_desc(subq);
+ }
if (fpin) {
fc_host_fpin_rcv(tgt->vhost->host,
sizeof(*fpin) +
be32_to_cpu(fpin->desc_len),
(char *)fpin, 0);
kfree(fpin);
} else
- dev_err_ratelimited(vhost->dev,
- "FPIN event %u received, unable to
process\n",
- crq->fpin_status);
+ dev_err_ratelimited(vhost->dev, "FPIN event received,
unable to process\n");
}
end:
- crq->valid = 0;
+ if (crq)
+ crq->valid = 0;
+ if (subq)
+ subq->valid = 0;
kfree(aw);
}
/**
- * ibmvfc_handle_async - Handle an async event from the adapter
- * @crq: crq to process
+ * ibmvfc_handle_async_common - Handle an async event from the adapter
+ * @event: event to process
+ * @link_state: link state
* @vhost: ibmvfc host struct
+ * @scsi_id: scsi_id (0 if not applicable)
+ * @wwpn: wwpn
+ * @node_name: node_name
+ * @aw_crq: crq pointer for async work (NULL if not needed)
+ * @aw_subq: subq pointer for async work (NULL if not needed)
*
**/
-VISIBLE_IF_KUNIT void ibmvfc_handle_async(struct ibmvfc_async_crq *crq,
- struct ibmvfc_host *vhost)
+static void ibmvfc_handle_async_common(u64 event, u8 link_state,
+ struct ibmvfc_host *vhost,
+ u64 scsi_id, u64 wwpn, u64 node_name,
+ struct ibmvfc_async_crq *aw_crq,
+ struct ibmvfc_async_subq *aw_subq)
{
- const struct ibmvfc_async_desc *desc =
ibmvfc_get_ae_desc(be64_to_cpu(crq->event));
+ struct ibmvfc_target *tgt, *next;
struct ibmvfc_async_work *aw;
- struct ibmvfc_target *tgt;
bool clear_valid = true;
- ibmvfc_log(vhost, desc->log_level, "%s event received. scsi_id: %llx,
wwpn: %llx,"
- " node_name: %llx%s\n", desc->desc,
be64_to_cpu(crq->scsi_id),
- be64_to_cpu(crq->wwpn), be64_to_cpu(crq->node_name),
- ibmvfc_get_link_state(crq->link_state));
-
- switch (be64_to_cpu(crq->event)) {
+ switch (event) {
case IBMVFC_AE_RESUME:
- switch (crq->link_state) {
+ switch (link_state) {
case IBMVFC_AE_LS_LINK_DOWN:
ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
break;
@@ -3419,7 +3484,6 @@ VISIBLE_IF_KUNIT void ibmvfc_handle_async(struct
ibmvfc_async_crq *crq,
__ibmvfc_reset_host(vhost);
break;
}
-
break;
case IBMVFC_AE_LINK_UP:
vhost->events_to_log |= IBMVFC_AE_LINKUP;
@@ -3439,58 +3503,106 @@ VISIBLE_IF_KUNIT void ibmvfc_handle_async(struct
ibmvfc_async_crq *crq,
vhost->events_to_log |= IBMVFC_AE_RSCN;
ibmvfc_reinit_host(vhost);
break;
+ case IBMVFC_AE_LINK_DOWN:
+ case IBMVFC_AE_ADAPTER_FAILED:
+ ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
+ break;
+ case IBMVFC_AE_LINK_DEAD:
+ ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
+ break;
+ case IBMVFC_AE_HALT:
+ ibmvfc_link_down(vhost, IBMVFC_HALTED);
+ break;
case IBMVFC_AE_ELS_LOGO:
case IBMVFC_AE_ELS_PRLO:
case IBMVFC_AE_ELS_PLOGI:
- list_for_each_entry(tgt, &vhost->targets, queue) {
- if (!crq->scsi_id && !crq->wwpn && !crq->node_name)
+ list_for_each_entry_safe(tgt, next, &vhost->targets, queue) {
+ if (!scsi_id && !wwpn && !node_name)
break;
- if (crq->scsi_id && cpu_to_be64(tgt->scsi_id) !=
crq->scsi_id)
+ if (scsi_id && cpu_to_be64(tgt->scsi_id) != scsi_id)
continue;
- if (crq->wwpn && cpu_to_be64(tgt->ids.port_name) !=
crq->wwpn)
+ if (wwpn && cpu_to_be64(tgt->ids.port_name) != wwpn)
continue;
- if (crq->node_name && cpu_to_be64(tgt->ids.node_name)
!= crq->node_name)
+ if (node_name && cpu_to_be64(tgt->ids.node_name) !=
node_name)
continue;
- if (tgt->need_login && be64_to_cpu(crq->event) ==
IBMVFC_AE_ELS_LOGO)
+ if (tgt->need_login && event == IBMVFC_AE_ELS_LOGO)
tgt->logo_rcvd = 1;
- if (!tgt->need_login || be64_to_cpu(crq->event) ==
IBMVFC_AE_ELS_PLOGI) {
+ if (!tgt->need_login || event == IBMVFC_AE_ELS_PLOGI) {
ibmvfc_del_tgt(tgt);
ibmvfc_reinit_host(vhost);
}
}
break;
- case IBMVFC_AE_LINK_DOWN:
- case IBMVFC_AE_ADAPTER_FAILED:
- ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
- break;
- case IBMVFC_AE_LINK_DEAD:
- ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
- break;
- case IBMVFC_AE_HALT:
- ibmvfc_link_down(vhost, IBMVFC_HALTED);
- break;
case IBMVFC_AE_FPIN:
aw = kzalloc(sizeof(struct ibmvfc_async_work), GFP_ATOMIC);
if (aw) {
clear_valid = false;
INIT_WORK(&aw->async_work_s, ibmvfc_process_async_work);
aw->vhost = vhost;
- aw->crq = crq;
+ if (aw_crq)
+ aw->crq = aw_crq;
+ if (aw_subq)
+ aw->subq = aw_subq;
schedule_work(&aw->async_work_s);
} else
dev_err_ratelimited(vhost->dev,
"can't offload async CRQ to work
queue\n");
break;
default:
- dev_err(vhost->dev, "Unknown async event received: %lld\n",
crq->event);
+ dev_err(vhost->dev, "Unknown async event received: %llu\n",
event);
break;
}
- if (clear_valid)
- crq->valid = 0;
+ if (clear_valid) {
+ if (aw_crq)
+ aw_crq->valid = 0;
+ if (aw_subq)
+ aw_subq->valid = 0;
+ }
+}
+
+/**
+ * ibmvfc_handle_async - Handle an async event from the adapter
+ * @crq: crq to process
+ * @vhost: ibmvfc host struct
+ *
+ **/
+VISIBLE_IF_KUNIT void ibmvfc_handle_async(struct ibmvfc_async_crq *crq,
+ struct ibmvfc_host *vhost)
+{
+ const struct ibmvfc_async_desc *desc =
ibmvfc_get_ae_desc(be64_to_cpu(crq->event));
+ u64 event = be64_to_cpu(crq->event);
+
+ ibmvfc_log(vhost, desc->log_level,
+ "%s event received. scsi_id: %llx, wwpn: %llx, node_name:
%llx%s\n",
+ desc->desc, be64_to_cpu(crq->scsi_id),
+ be64_to_cpu(crq->wwpn), be64_to_cpu(crq->node_name),
+ ibmvfc_get_link_state(crq->link_state));
+
+ ibmvfc_handle_async_common(event, crq->link_state, vhost,
+ crq->scsi_id, crq->wwpn, crq->node_name,
+ crq, NULL);
}
EXPORT_SYMBOL_IF_KUNIT(ibmvfc_handle_async);
+VISIBLE_IF_KUNIT void ibmvfc_handle_asyncq(struct ibmvfc_crq *crq_instance,
+ struct ibmvfc_host *vhost)
+{
+ struct ibmvfc_async_subq *crq = (struct ibmvfc_async_subq
*)crq_instance;
+ const struct ibmvfc_async_desc *desc =
ibmvfc_get_ae_desc(be16_to_cpu(crq->event));
+ u64 event = be16_to_cpu(crq->event);
+
+ ibmvfc_log(vhost, desc->log_level,
+ "%s event received. wwpn: %llx, node_name: %llx%s event
0x%x\n",
+ desc->desc, be64_to_cpu(crq->wwpn),
be64_to_cpu(crq->id.node_name),
+ ibmvfc_get_link_state(crq->link_state),
be16_to_cpu(crq->event));
+
+ ibmvfc_handle_async_common(event, crq->link_state, vhost,
+ 0, crq->wwpn, crq->id.node_name,
+ NULL, crq);
+}
+EXPORT_SYMBOL_IF_KUNIT(ibmvfc_handle_asyncq);
+
/**
* ibmvfc_handle_crq - Handles and frees received events in the CRQ
* @crq: Command/Response queue
@@ -4117,6 +4229,13 @@ static void ibmvfc_handle_scrq(struct ibmvfc_crq *crq,
struct ibmvfc_host *vhost
spin_unlock(&evt->queue->l_lock);
}
+/**
+ * ibmvfc_next_scrq - Returns the next entry in message subqueue
+ * @scrq: Pointer to message subqueue
+ *
+ * Returns:
+ * Pointer to next entry in queue / NULL if empty
+ **/
static struct ibmvfc_crq *ibmvfc_next_scrq(struct ibmvfc_queue *scrq)
{
struct ibmvfc_crq *crq;
@@ -4132,6 +4251,57 @@ static struct ibmvfc_crq *ibmvfc_next_scrq(struct
ibmvfc_queue *scrq)
return crq;
}
+static void ibmvfc_drain_async_subq(struct ibmvfc_queue *scrq)
+{
+ struct ibmvfc_crq *crq;
+ unsigned long flags;
+ int done = 0;
+
+ ENTER;
+
+ spin_lock_irqsave(scrq->q_lock, flags);
+ while (!done) {
+ while ((crq = ibmvfc_next_scrq(scrq)) != NULL) {
+ ibmvfc_handle_asyncq(crq, scrq->vhost);
+ crq->valid = 0;
+ wmb(); /* complete write */
+ }
+
+ ibmvfc_toggle_scrq_irq(scrq, 1);
+ crq = ibmvfc_next_scrq(scrq);
+ if (crq != NULL) {
+ ibmvfc_toggle_scrq_irq(scrq, 0);
+ ibmvfc_handle_asyncq(crq, scrq->vhost);
+ crq->valid = 0;
+ wmb(); /* complete write */
+ } else
+ done = 1;
+ }
+ spin_unlock_irqrestore(scrq->q_lock, flags);
+
+ LEAVE;
+}
+
+/**
+ * ibmvfc_interrupt_asyncq - Handle an async event from the adapter
+ * @irq: interrupt request
+ * @scrq_instance: async subq
+ *
+ **/
+static irqreturn_t ibmvfc_interrupt_asyncq(int irq, void *scrq_instance)
+{
+ struct ibmvfc_queue *scrq = (struct ibmvfc_queue *)scrq_instance;
+
+ ENTER;
+
+ ibmvfc_toggle_scrq_irq(scrq, 0);
+ ibmvfc_drain_async_subq(scrq);
+
+ LEAVE;
+
+ return IRQ_HANDLED;
+}
+
static void ibmvfc_drain_sub_crq(struct ibmvfc_queue *scrq)
{
struct ibmvfc_crq *crq;
@@ -5500,6 +5670,8 @@ static void ibmvfc_npiv_login_done(struct ibmvfc_event
*evt)
unsigned int npiv_max_sectors;
int level = IBMVFC_DEFAULT_LOG_LEVEL;
+ ENTER;
+
switch (mad_status) {
case IBMVFC_MAD_SUCCESS:
ibmvfc_free_event(evt);
@@ -5578,6 +5750,8 @@ static void ibmvfc_npiv_login_done(struct ibmvfc_event
*evt)
ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
wake_up(&vhost->work_wait_q);
}
+
+ LEAVE;
}
/**
@@ -6226,14 +6400,26 @@ static int ibmvfc_init_crq(struct ibmvfc_host *vhost)
return retrc;
}
-static int ibmvfc_register_channel(struct ibmvfc_host *vhost,
- struct ibmvfc_channels *channels,
- int index)
+static inline char *ibmvfc_channel_index(struct ibmvfc_channels *channels,
+ struct ibmvfc_queue *scrq,
+ char *buf, size_t bufsize)
+{
+ if (scrq < channels->scrqs || scrq >= channels->scrqs +
channels->active_queues)
+ strscpy(buf, "async", 6);
+ else
+ snprintf(buf, bufsize, "%ld", scrq - channels->scrqs);
+ return buf;
+}
+
+static int ibmvfc_register_channel_handler(struct ibmvfc_host *vhost,
+ struct ibmvfc_channels *channels,
+ struct ibmvfc_queue *scrq,
+ irq_handler_t irq)
{
struct device *dev = vhost->dev;
struct vio_dev *vdev = to_vio_dev(dev);
- struct ibmvfc_queue *scrq = &channels->scrqs[index];
int rc = -ENOMEM;
+ char buf[16];
ENTER;
@@ -6252,20 +6438,23 @@ static int ibmvfc_register_channel(struct ibmvfc_host
*vhost,
if (!scrq->irq) {
rc = -EINVAL;
- dev_err(dev, "Error mapping sub-crq[%d] irq\n", index);
+ dev_err(dev, "Error mapping sub-crq[%s] irq\n",
+ ibmvfc_channel_index(channels, scrq, buf, sizeof(buf)));
goto irq_failed;
}
switch (channels->protocol) {
case IBMVFC_PROTO_SCSI:
- snprintf(scrq->name, sizeof(scrq->name), "ibmvfc-%x-scsi%d",
- vdev->unit_address, index);
- scrq->handler = ibmvfc_interrupt_mq;
+ snprintf(scrq->name, sizeof(scrq->name), "ibmvfc-%x-scsi%s",
+ vdev->unit_address,
+ ibmvfc_channel_index(channels, scrq, buf,
sizeof(buf)));
+ scrq->handler = irq;
break;
case IBMVFC_PROTO_NVME:
- snprintf(scrq->name, sizeof(scrq->name), "ibmvfc-%x-nvmf%d",
- vdev->unit_address, index);
- scrq->handler = ibmvfc_interrupt_mq;
+ snprintf(scrq->name, sizeof(scrq->name), "ibmvfc-%x-nvmf%s",
+ vdev->unit_address,
+ ibmvfc_channel_index(channels, scrq, buf,
sizeof(buf)));
+ scrq->handler = irq;
break;
default:
dev_err(dev, "Unknown channel protocol (%d)\n",
@@ -6276,12 +6465,14 @@ static int ibmvfc_register_channel(struct ibmvfc_host
*vhost,
rc = request_irq(scrq->irq, scrq->handler, 0, scrq->name, scrq);
if (rc) {
- dev_err(dev, "Couldn't register sub-crq[%d] irq\n", index);
+ dev_err(dev, "Couldn't register sub-crq[%s] irq\n",
+ ibmvfc_channel_index(channels, scrq, buf, sizeof(buf)));
irq_dispose_mapping(scrq->irq);
goto irq_failed;
}
- scrq->hwq_id = index;
+ if (scrq >= channels->scrqs && scrq < channels->scrqs +
channels->max_queues)
+ scrq->hwq_id = scrq - channels->scrqs;
LEAVE;
return 0;
@@ -6295,13 +6486,21 @@ static int ibmvfc_register_channel(struct ibmvfc_host
*vhost,
return rc;
}
+static inline int
+ibmvfc_register_channel(struct ibmvfc_host *vhost,
+ struct ibmvfc_channels *channels,
+ struct ibmvfc_queue *scrq)
+{
+ return ibmvfc_register_channel_handler(vhost, channels, scrq,
ibmvfc_interrupt_mq);
+}
+
static void ibmvfc_deregister_channel(struct ibmvfc_host *vhost,
struct ibmvfc_channels *channels,
- int index)
+ struct ibmvfc_queue *scrq)
{
struct device *dev = vhost->dev;
struct vio_dev *vdev = to_vio_dev(dev);
- struct ibmvfc_queue *scrq = &channels->scrqs[index];
+ char buf[16];
long rc;
ENTER;
@@ -6316,7 +6515,8 @@ static void ibmvfc_deregister_channel(struct ibmvfc_host
*vhost,
} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
if (rc)
- dev_err(dev, "Failed to free sub-crq[%d]: rc=%ld\n", index, rc);
+ dev_err(dev, "Failed to free sub-crq[%s]: rc=%ld\n",
+ ibmvfc_channel_index(channels, scrq, buf, sizeof(buf)),
rc);
/* Clean out the queue */
memset(scrq->msgs.crq, 0, PAGE_SIZE);
@@ -6334,10 +6534,21 @@ static void ibmvfc_reg_sub_crqs(struct ibmvfc_host
*vhost,
if (!vhost->mq_enabled || !channels->scrqs)
return;
+ if (ibmvfc_register_channel_handler(vhost, channels,
+ channels->async_scrq,
+ ibmvfc_interrupt_asyncq)) {
+ vhost->do_enquiry = 0;
+ return;
+ }
+
for (i = 0; i < channels->max_queues; i++) {
- if (ibmvfc_register_channel(vhost, channels, i)) {
+ if (ibmvfc_register_channel(vhost, channels,
&channels->scrqs[i])) {
for (j = i; j > 0; j--)
- ibmvfc_deregister_channel(vhost, channels, j -
1);
+ ibmvfc_deregister_channel(
+ vhost, channels, &channels->scrqs[j -
1]);
+ ibmvfc_deregister_channel(vhost, channels,
+ channels->async_scrq);
+
vhost->do_enquiry = 0;
return;
}
@@ -6356,7 +6567,8 @@ static void ibmvfc_dereg_sub_crqs(struct ibmvfc_host
*vhost,
return;
for (i = 0; i < channels->max_queues; i++)
- ibmvfc_deregister_channel(vhost, channels, i);
+ ibmvfc_deregister_channel(vhost, channels, &channels->scrqs[i]);
+ ibmvfc_deregister_channel(vhost, channels, channels->async_scrq);
LEAVE;
}
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h
index f026f30f98d3..2e02acde0178 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.h
+++ b/drivers/scsi/ibmvscsi/ibmvfc.h
@@ -715,6 +715,7 @@ struct ibmvfc_async_crq {
struct ibmvfc_async_work {
struct ibmvfc_host *vhost;
struct ibmvfc_async_crq *crq;
+ struct ibmvfc_async_subq *subq;
struct work_struct async_work_s;
};
@@ -1008,6 +1009,8 @@ struct ibmvfc_host {
#ifdef VISIBLE_IF_KUNIT
VISIBLE_IF_KUNIT void ibmvfc_handle_async(struct ibmvfc_async_crq *crq, struct
ibmvfc_host *vhost);
+VISIBLE_IF_KUNIT void ibmvfc_handle_asyncq(struct ibmvfc_crq *crq_instance,
+ struct ibmvfc_host *vhost);
VISIBLE_IF_KUNIT struct list_head *ibmvfc_get_headp(void);
#endif
diff --git a/drivers/scsi/ibmvscsi/ibmvfc_kunit.c
b/drivers/scsi/ibmvscsi/ibmvfc_kunit.c
index e41e2a49e549..c8799eaf4927 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc_kunit.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc_kunit.c
@@ -44,7 +44,7 @@ static void ibmvfc_async_fpin_test(struct kunit *test)
fc_host = shost_to_fc_host(vhost->host);
pre[IBMVFC_AE_FPIN_LINK_CONGESTED] =
READ_ONCE(fc_host->fpin_stats.cn_device_specific);
- pre[IBMVFC_AE_FPIN_PORT_CONGESTED] =
READ_ONCE(tgt->rport->fpin_stats.cn);
+ pre[IBMVFC_AE_FPIN_PORT_CONGESTED] =
READ_ONCE(tgt->rport->fpin_stats.cn_device_specific);
pre[IBMVFC_AE_FPIN_PORT_CLEARED] =
READ_ONCE(tgt->rport->fpin_stats.cn_clear);
pre[IBMVFC_AE_FPIN_PORT_DEGRADED] =
READ_ONCE(tgt->rport->fpin_stats.li_failure_unknown);
pre[IBMVFC_AE_FPIN_CONGESTION_CLEARED] =
READ_ONCE(fc_host->fpin_stats.cn_clear);
--
2.54.0