Commit dc718994 authored by Martin K. Petersen's avatar Martin K. Petersen

Merge patch series "ibmvfc: fixes and generic prep work for NVMeoF support"

Tyrel Datwyler <tyreld@linux.ibm.com> says:

This series includes a couple minor fixes, generalization of some code
that is not protocol specific, and a reworking of the way event pool
buffers are accounted for by the driver. This is a precursor to a
series to follow that introduces support for NVMeoF protocol with
ibmvfc.

Link: https://lore.kernel.org/r/20230921225435.3537728-1-tyreld@linux.ibm.comSigned-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parents 5ef104b7 02e2d8f4
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
#include <linux/bsg-lib.h> #include <linux/bsg-lib.h>
#include <asm/firmware.h> #include <asm/firmware.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/rtas.h>
#include <asm/vio.h> #include <asm/vio.h>
#include <scsi/scsi.h> #include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h> #include <scsi/scsi_cmnd.h>
...@@ -38,6 +37,7 @@ static unsigned int default_timeout = IBMVFC_DEFAULT_TIMEOUT; ...@@ -38,6 +37,7 @@ static unsigned int default_timeout = IBMVFC_DEFAULT_TIMEOUT;
static u64 max_lun = IBMVFC_MAX_LUN; static u64 max_lun = IBMVFC_MAX_LUN;
static unsigned int max_targets = IBMVFC_MAX_TARGETS; static unsigned int max_targets = IBMVFC_MAX_TARGETS;
static unsigned int max_requests = IBMVFC_MAX_REQUESTS_DEFAULT; static unsigned int max_requests = IBMVFC_MAX_REQUESTS_DEFAULT;
static u16 scsi_qdepth = IBMVFC_SCSI_QDEPTH;
static unsigned int disc_threads = IBMVFC_MAX_DISC_THREADS; static unsigned int disc_threads = IBMVFC_MAX_DISC_THREADS;
static unsigned int ibmvfc_debug = IBMVFC_DEBUG; static unsigned int ibmvfc_debug = IBMVFC_DEBUG;
static unsigned int log_level = IBMVFC_DEFAULT_LOG_LEVEL; static unsigned int log_level = IBMVFC_DEFAULT_LOG_LEVEL;
...@@ -83,6 +83,9 @@ MODULE_PARM_DESC(default_timeout, ...@@ -83,6 +83,9 @@ MODULE_PARM_DESC(default_timeout,
module_param_named(max_requests, max_requests, uint, S_IRUGO); module_param_named(max_requests, max_requests, uint, S_IRUGO);
MODULE_PARM_DESC(max_requests, "Maximum requests for this adapter. " MODULE_PARM_DESC(max_requests, "Maximum requests for this adapter. "
"[Default=" __stringify(IBMVFC_MAX_REQUESTS_DEFAULT) "]"); "[Default=" __stringify(IBMVFC_MAX_REQUESTS_DEFAULT) "]");
module_param_named(scsi_qdepth, scsi_qdepth, ushort, S_IRUGO);
MODULE_PARM_DESC(scsi_qdepth, "Maximum scsi command depth per adapter queue. "
"[Default=" __stringify(IBMVFC_SCSI_QDEPTH) "]");
module_param_named(max_lun, max_lun, ullong, S_IRUGO); module_param_named(max_lun, max_lun, ullong, S_IRUGO);
MODULE_PARM_DESC(max_lun, "Maximum allowed LUN. " MODULE_PARM_DESC(max_lun, "Maximum allowed LUN. "
"[Default=" __stringify(IBMVFC_MAX_LUN) "]"); "[Default=" __stringify(IBMVFC_MAX_LUN) "]");
...@@ -160,8 +163,8 @@ static void ibmvfc_npiv_logout(struct ibmvfc_host *); ...@@ -160,8 +163,8 @@ static void ibmvfc_npiv_logout(struct ibmvfc_host *);
static void ibmvfc_tgt_implicit_logout_and_del(struct ibmvfc_target *); static void ibmvfc_tgt_implicit_logout_and_del(struct ibmvfc_target *);
static void ibmvfc_tgt_move_login(struct ibmvfc_target *); static void ibmvfc_tgt_move_login(struct ibmvfc_target *);
static void ibmvfc_dereg_sub_crqs(struct ibmvfc_host *); static void ibmvfc_dereg_sub_crqs(struct ibmvfc_host *, struct ibmvfc_channels *);
static void ibmvfc_reg_sub_crqs(struct ibmvfc_host *); static void ibmvfc_reg_sub_crqs(struct ibmvfc_host *, struct ibmvfc_channels *);
static const char *unknown_error = "unknown error"; static const char *unknown_error = "unknown error";
...@@ -776,28 +779,26 @@ static int ibmvfc_send_crq_init_complete(struct ibmvfc_host *vhost) ...@@ -776,28 +779,26 @@ static int ibmvfc_send_crq_init_complete(struct ibmvfc_host *vhost)
* ibmvfc_init_event_pool - Allocates and initializes the event pool for a host * ibmvfc_init_event_pool - Allocates and initializes the event pool for a host
* @vhost: ibmvfc host who owns the event pool * @vhost: ibmvfc host who owns the event pool
* @queue: ibmvfc queue struct * @queue: ibmvfc queue struct
* @size: pool size
* *
* Returns zero on success. * Returns zero on success.
**/ **/
static int ibmvfc_init_event_pool(struct ibmvfc_host *vhost, static int ibmvfc_init_event_pool(struct ibmvfc_host *vhost,
struct ibmvfc_queue *queue, struct ibmvfc_queue *queue)
unsigned int size)
{ {
int i; int i;
struct ibmvfc_event_pool *pool = &queue->evt_pool; struct ibmvfc_event_pool *pool = &queue->evt_pool;
ENTER; ENTER;
if (!size) if (!queue->total_depth)
return 0; return 0;
pool->size = size; pool->size = queue->total_depth;
pool->events = kcalloc(size, sizeof(*pool->events), GFP_KERNEL); pool->events = kcalloc(pool->size, sizeof(*pool->events), GFP_KERNEL);
if (!pool->events) if (!pool->events)
return -ENOMEM; return -ENOMEM;
pool->iu_storage = dma_alloc_coherent(vhost->dev, pool->iu_storage = dma_alloc_coherent(vhost->dev,
size * sizeof(*pool->iu_storage), pool->size * sizeof(*pool->iu_storage),
&pool->iu_token, 0); &pool->iu_token, 0);
if (!pool->iu_storage) { if (!pool->iu_storage) {
...@@ -807,9 +808,11 @@ static int ibmvfc_init_event_pool(struct ibmvfc_host *vhost, ...@@ -807,9 +808,11 @@ static int ibmvfc_init_event_pool(struct ibmvfc_host *vhost,
INIT_LIST_HEAD(&queue->sent); INIT_LIST_HEAD(&queue->sent);
INIT_LIST_HEAD(&queue->free); INIT_LIST_HEAD(&queue->free);
queue->evt_free = queue->evt_depth;
queue->reserved_free = queue->reserved_depth;
spin_lock_init(&queue->l_lock); spin_lock_init(&queue->l_lock);
for (i = 0; i < size; ++i) { for (i = 0; i < pool->size; ++i) {
struct ibmvfc_event *evt = &pool->events[i]; struct ibmvfc_event *evt = &pool->events[i];
/* /*
...@@ -922,7 +925,7 @@ static int ibmvfc_reenable_crq_queue(struct ibmvfc_host *vhost) ...@@ -922,7 +925,7 @@ static int ibmvfc_reenable_crq_queue(struct ibmvfc_host *vhost)
struct vio_dev *vdev = to_vio_dev(vhost->dev); struct vio_dev *vdev = to_vio_dev(vhost->dev);
unsigned long flags; unsigned long flags;
ibmvfc_dereg_sub_crqs(vhost); ibmvfc_dereg_sub_crqs(vhost, &vhost->scsi_scrqs);
/* Re-enable the CRQ */ /* Re-enable the CRQ */
do { do {
...@@ -941,7 +944,7 @@ static int ibmvfc_reenable_crq_queue(struct ibmvfc_host *vhost) ...@@ -941,7 +944,7 @@ static int ibmvfc_reenable_crq_queue(struct ibmvfc_host *vhost)
spin_unlock(vhost->crq.q_lock); spin_unlock(vhost->crq.q_lock);
spin_unlock_irqrestore(vhost->host->host_lock, flags); spin_unlock_irqrestore(vhost->host->host_lock, flags);
ibmvfc_reg_sub_crqs(vhost); ibmvfc_reg_sub_crqs(vhost, &vhost->scsi_scrqs);
return rc; return rc;
} }
...@@ -960,7 +963,7 @@ static int ibmvfc_reset_crq(struct ibmvfc_host *vhost) ...@@ -960,7 +963,7 @@ static int ibmvfc_reset_crq(struct ibmvfc_host *vhost)
struct vio_dev *vdev = to_vio_dev(vhost->dev); struct vio_dev *vdev = to_vio_dev(vhost->dev);
struct ibmvfc_queue *crq = &vhost->crq; struct ibmvfc_queue *crq = &vhost->crq;
ibmvfc_dereg_sub_crqs(vhost); ibmvfc_dereg_sub_crqs(vhost, &vhost->scsi_scrqs);
/* Close the CRQ */ /* Close the CRQ */
do { do {
...@@ -993,7 +996,7 @@ static int ibmvfc_reset_crq(struct ibmvfc_host *vhost) ...@@ -993,7 +996,7 @@ static int ibmvfc_reset_crq(struct ibmvfc_host *vhost)
spin_unlock(vhost->crq.q_lock); spin_unlock(vhost->crq.q_lock);
spin_unlock_irqrestore(vhost->host->host_lock, flags); spin_unlock_irqrestore(vhost->host->host_lock, flags);
ibmvfc_reg_sub_crqs(vhost); ibmvfc_reg_sub_crqs(vhost, &vhost->scsi_scrqs);
return rc; return rc;
} }
...@@ -1033,6 +1036,12 @@ static void ibmvfc_free_event(struct ibmvfc_event *evt) ...@@ -1033,6 +1036,12 @@ static void ibmvfc_free_event(struct ibmvfc_event *evt)
spin_lock_irqsave(&evt->queue->l_lock, flags); spin_lock_irqsave(&evt->queue->l_lock, flags);
list_add_tail(&evt->queue_list, &evt->queue->free); list_add_tail(&evt->queue_list, &evt->queue->free);
if (evt->reserved) {
evt->reserved = 0;
evt->queue->reserved_free++;
} else {
evt->queue->evt_free++;
}
if (evt->eh_comp) if (evt->eh_comp)
complete(evt->eh_comp); complete(evt->eh_comp);
spin_unlock_irqrestore(&evt->queue->l_lock, flags); spin_unlock_irqrestore(&evt->queue->l_lock, flags);
...@@ -1475,6 +1484,12 @@ static void ibmvfc_set_login_info(struct ibmvfc_host *vhost) ...@@ -1475,6 +1484,12 @@ static void ibmvfc_set_login_info(struct ibmvfc_host *vhost)
struct ibmvfc_queue *async_crq = &vhost->async_crq; struct ibmvfc_queue *async_crq = &vhost->async_crq;
struct device_node *of_node = vhost->dev->of_node; struct device_node *of_node = vhost->dev->of_node;
const char *location; const char *location;
u16 max_cmds;
max_cmds = scsi_qdepth + IBMVFC_NUM_INTERNAL_REQ;
if (mq_enabled)
max_cmds += (scsi_qdepth + IBMVFC_NUM_INTERNAL_SUBQ_REQ) *
vhost->scsi_scrqs.desired_queues;
memset(login_info, 0, sizeof(*login_info)); memset(login_info, 0, sizeof(*login_info));
...@@ -1489,7 +1504,7 @@ static void ibmvfc_set_login_info(struct ibmvfc_host *vhost) ...@@ -1489,7 +1504,7 @@ static void ibmvfc_set_login_info(struct ibmvfc_host *vhost)
if (vhost->client_migrated) if (vhost->client_migrated)
login_info->flags |= cpu_to_be16(IBMVFC_CLIENT_MIGRATED); login_info->flags |= cpu_to_be16(IBMVFC_CLIENT_MIGRATED);
login_info->max_cmds = cpu_to_be32(max_requests + IBMVFC_NUM_INTERNAL_REQ); login_info->max_cmds = cpu_to_be32(max_cmds);
login_info->capabilities = cpu_to_be64(IBMVFC_CAN_MIGRATE | IBMVFC_CAN_SEND_VF_WWPN); login_info->capabilities = cpu_to_be64(IBMVFC_CAN_MIGRATE | IBMVFC_CAN_SEND_VF_WWPN);
if (vhost->mq_enabled || vhost->using_channels) if (vhost->mq_enabled || vhost->using_channels)
...@@ -1508,25 +1523,39 @@ static void ibmvfc_set_login_info(struct ibmvfc_host *vhost) ...@@ -1508,25 +1523,39 @@ static void ibmvfc_set_login_info(struct ibmvfc_host *vhost)
} }
/** /**
* ibmvfc_get_event - Gets the next free event in pool * __ibmvfc_get_event - Gets the next free event in pool
* @queue: ibmvfc queue struct * @queue: ibmvfc queue struct
* @reserved: event is for a reserved management command
* *
* Returns a free event from the pool. * Returns a free event from the pool.
**/ **/
static struct ibmvfc_event *ibmvfc_get_event(struct ibmvfc_queue *queue) static struct ibmvfc_event *__ibmvfc_get_event(struct ibmvfc_queue *queue, int reserved)
{ {
struct ibmvfc_event *evt; struct ibmvfc_event *evt = NULL;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&queue->l_lock, flags); spin_lock_irqsave(&queue->l_lock, flags);
BUG_ON(list_empty(&queue->free)); if (reserved && queue->reserved_free) {
evt = list_entry(queue->free.next, struct ibmvfc_event, queue_list); evt = list_entry(queue->free.next, struct ibmvfc_event, queue_list);
evt->reserved = 1;
queue->reserved_free--;
} else if (queue->evt_free) {
evt = list_entry(queue->free.next, struct ibmvfc_event, queue_list);
queue->evt_free--;
} else {
goto out;
}
atomic_set(&evt->free, 0); atomic_set(&evt->free, 0);
list_del(&evt->queue_list); list_del(&evt->queue_list);
out:
spin_unlock_irqrestore(&queue->l_lock, flags); spin_unlock_irqrestore(&queue->l_lock, flags);
return evt; return evt;
} }
#define ibmvfc_get_event(queue) __ibmvfc_get_event(queue, 0)
#define ibmvfc_get_reserved_event(queue) __ibmvfc_get_event(queue, 1)
/** /**
* ibmvfc_locked_done - Calls evt completion with host_lock held * ibmvfc_locked_done - Calls evt completion with host_lock held
* @evt: ibmvfc evt to complete * @evt: ibmvfc evt to complete
...@@ -1948,9 +1977,15 @@ static int ibmvfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) ...@@ -1948,9 +1977,15 @@ static int ibmvfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
if (vhost->using_channels) { if (vhost->using_channels) {
scsi_channel = hwq % vhost->scsi_scrqs.active_queues; scsi_channel = hwq % vhost->scsi_scrqs.active_queues;
evt = ibmvfc_get_event(&vhost->scsi_scrqs.scrqs[scsi_channel]); evt = ibmvfc_get_event(&vhost->scsi_scrqs.scrqs[scsi_channel]);
if (!evt)
return SCSI_MLQUEUE_HOST_BUSY;
evt->hwq = hwq % vhost->scsi_scrqs.active_queues; evt->hwq = hwq % vhost->scsi_scrqs.active_queues;
} else } else {
evt = ibmvfc_get_event(&vhost->crq); evt = ibmvfc_get_event(&vhost->crq);
if (!evt)
return SCSI_MLQUEUE_HOST_BUSY;
}
ibmvfc_init_event(evt, ibmvfc_scsi_done, IBMVFC_CMD_FORMAT); ibmvfc_init_event(evt, ibmvfc_scsi_done, IBMVFC_CMD_FORMAT);
evt->cmnd = cmnd; evt->cmnd = cmnd;
...@@ -2037,7 +2072,12 @@ static int ibmvfc_bsg_timeout(struct bsg_job *job) ...@@ -2037,7 +2072,12 @@ static int ibmvfc_bsg_timeout(struct bsg_job *job)
} }
vhost->aborting_passthru = 1; vhost->aborting_passthru = 1;
evt = ibmvfc_get_event(&vhost->crq); evt = ibmvfc_get_reserved_event(&vhost->crq);
if (!evt) {
spin_unlock_irqrestore(vhost->host->host_lock, flags);
return -ENOMEM;
}
ibmvfc_init_event(evt, ibmvfc_bsg_timeout_done, IBMVFC_MAD_FORMAT); ibmvfc_init_event(evt, ibmvfc_bsg_timeout_done, IBMVFC_MAD_FORMAT);
tmf = &evt->iu.tmf; tmf = &evt->iu.tmf;
...@@ -2095,7 +2135,11 @@ static int ibmvfc_bsg_plogi(struct ibmvfc_host *vhost, unsigned int port_id) ...@@ -2095,7 +2135,11 @@ static int ibmvfc_bsg_plogi(struct ibmvfc_host *vhost, unsigned int port_id)
if (unlikely((rc = ibmvfc_host_chkready(vhost)))) if (unlikely((rc = ibmvfc_host_chkready(vhost))))
goto unlock_out; goto unlock_out;
evt = ibmvfc_get_event(&vhost->crq); evt = ibmvfc_get_reserved_event(&vhost->crq);
if (!evt) {
rc = -ENOMEM;
goto unlock_out;
}
ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_MAD_FORMAT); ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_MAD_FORMAT);
plogi = &evt->iu.plogi; plogi = &evt->iu.plogi;
memset(plogi, 0, sizeof(*plogi)); memset(plogi, 0, sizeof(*plogi));
...@@ -2213,7 +2257,12 @@ static int ibmvfc_bsg_request(struct bsg_job *job) ...@@ -2213,7 +2257,12 @@ static int ibmvfc_bsg_request(struct bsg_job *job)
goto out; goto out;
} }
evt = ibmvfc_get_event(&vhost->crq); evt = ibmvfc_get_reserved_event(&vhost->crq);
if (!evt) {
spin_unlock_irqrestore(vhost->host->host_lock, flags);
rc = -ENOMEM;
goto out;
}
ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_MAD_FORMAT); ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_MAD_FORMAT);
mad = &evt->iu.passthru; mad = &evt->iu.passthru;
...@@ -2302,6 +2351,11 @@ static int ibmvfc_reset_device(struct scsi_device *sdev, int type, char *desc) ...@@ -2302,6 +2351,11 @@ static int ibmvfc_reset_device(struct scsi_device *sdev, int type, char *desc)
else else
evt = ibmvfc_get_event(&vhost->crq); evt = ibmvfc_get_event(&vhost->crq);
if (!evt) {
spin_unlock_irqrestore(vhost->host->host_lock, flags);
return -ENOMEM;
}
ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_CMD_FORMAT); ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_CMD_FORMAT);
tmf = ibmvfc_init_vfc_cmd(evt, sdev); tmf = ibmvfc_init_vfc_cmd(evt, sdev);
iu = ibmvfc_get_fcp_iu(vhost, tmf); iu = ibmvfc_get_fcp_iu(vhost, tmf);
...@@ -2504,7 +2558,9 @@ static struct ibmvfc_event *ibmvfc_init_tmf(struct ibmvfc_queue *queue, ...@@ -2504,7 +2558,9 @@ static struct ibmvfc_event *ibmvfc_init_tmf(struct ibmvfc_queue *queue,
struct ibmvfc_event *evt; struct ibmvfc_event *evt;
struct ibmvfc_tmf *tmf; struct ibmvfc_tmf *tmf;
evt = ibmvfc_get_event(queue); evt = ibmvfc_get_reserved_event(queue);
if (!evt)
return NULL;
ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_MAD_FORMAT); ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_MAD_FORMAT);
tmf = &evt->iu.tmf; tmf = &evt->iu.tmf;
...@@ -2561,6 +2617,11 @@ static int ibmvfc_cancel_all_mq(struct scsi_device *sdev, int type) ...@@ -2561,6 +2617,11 @@ static int ibmvfc_cancel_all_mq(struct scsi_device *sdev, int type)
if (found_evt && vhost->logged_in) { if (found_evt && vhost->logged_in) {
evt = ibmvfc_init_tmf(&queues[i], sdev, type); evt = ibmvfc_init_tmf(&queues[i], sdev, type);
if (!evt) {
spin_unlock(queues[i].q_lock);
spin_unlock_irqrestore(vhost->host->host_lock, flags);
return -ENOMEM;
}
evt->sync_iu = &queues[i].cancel_rsp; evt->sync_iu = &queues[i].cancel_rsp;
ibmvfc_send_event(evt, vhost, default_timeout); ibmvfc_send_event(evt, vhost, default_timeout);
list_add_tail(&evt->cancel, &cancelq); list_add_tail(&evt->cancel, &cancelq);
...@@ -2774,6 +2835,10 @@ static int ibmvfc_abort_task_set(struct scsi_device *sdev) ...@@ -2774,6 +2835,10 @@ static int ibmvfc_abort_task_set(struct scsi_device *sdev)
if (vhost->state == IBMVFC_ACTIVE) { if (vhost->state == IBMVFC_ACTIVE) {
evt = ibmvfc_get_event(&vhost->crq); evt = ibmvfc_get_event(&vhost->crq);
if (!evt) {
spin_unlock_irqrestore(vhost->host->host_lock, flags);
return -ENOMEM;
}
ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_CMD_FORMAT); ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_CMD_FORMAT);
tmf = ibmvfc_init_vfc_cmd(evt, sdev); tmf = ibmvfc_init_vfc_cmd(evt, sdev);
iu = ibmvfc_get_fcp_iu(vhost, tmf); iu = ibmvfc_get_fcp_iu(vhost, tmf);
...@@ -3513,11 +3578,12 @@ static ssize_t ibmvfc_show_scsi_channels(struct device *dev, ...@@ -3513,11 +3578,12 @@ static ssize_t ibmvfc_show_scsi_channels(struct device *dev,
{ {
struct Scsi_Host *shost = class_to_shost(dev); struct Scsi_Host *shost = class_to_shost(dev);
struct ibmvfc_host *vhost = shost_priv(shost); struct ibmvfc_host *vhost = shost_priv(shost);
struct ibmvfc_channels *scsi = &vhost->scsi_scrqs;
unsigned long flags = 0; unsigned long flags = 0;
int len; int len;
spin_lock_irqsave(shost->host_lock, flags); spin_lock_irqsave(shost->host_lock, flags);
len = snprintf(buf, PAGE_SIZE, "%d\n", vhost->client_scsi_channels); len = snprintf(buf, PAGE_SIZE, "%d\n", scsi->desired_queues);
spin_unlock_irqrestore(shost->host_lock, flags); spin_unlock_irqrestore(shost->host_lock, flags);
return len; return len;
} }
...@@ -3528,12 +3594,13 @@ static ssize_t ibmvfc_store_scsi_channels(struct device *dev, ...@@ -3528,12 +3594,13 @@ static ssize_t ibmvfc_store_scsi_channels(struct device *dev,
{ {
struct Scsi_Host *shost = class_to_shost(dev); struct Scsi_Host *shost = class_to_shost(dev);
struct ibmvfc_host *vhost = shost_priv(shost); struct ibmvfc_host *vhost = shost_priv(shost);
struct ibmvfc_channels *scsi = &vhost->scsi_scrqs;
unsigned long flags = 0; unsigned long flags = 0;
unsigned int channels; unsigned int channels;
spin_lock_irqsave(shost->host_lock, flags); spin_lock_irqsave(shost->host_lock, flags);
channels = simple_strtoul(buf, NULL, 10); channels = simple_strtoul(buf, NULL, 10);
vhost->client_scsi_channels = min(channels, nr_scsi_hw_queues); scsi->desired_queues = min(channels, shost->nr_hw_queues);
ibmvfc_hard_reset_host(vhost); ibmvfc_hard_reset_host(vhost);
spin_unlock_irqrestore(shost->host_lock, flags); spin_unlock_irqrestore(shost->host_lock, flags);
return strlen(buf); return strlen(buf);
...@@ -3633,7 +3700,6 @@ static const struct scsi_host_template driver_template = { ...@@ -3633,7 +3700,6 @@ static const struct scsi_host_template driver_template = {
.max_sectors = IBMVFC_MAX_SECTORS, .max_sectors = IBMVFC_MAX_SECTORS,
.shost_groups = ibmvfc_host_groups, .shost_groups = ibmvfc_host_groups,
.track_queue_depth = 1, .track_queue_depth = 1,
.host_tagset = 1,
}; };
/** /**
...@@ -3869,7 +3935,7 @@ static void ibmvfc_drain_sub_crq(struct ibmvfc_queue *scrq) ...@@ -3869,7 +3935,7 @@ static void ibmvfc_drain_sub_crq(struct ibmvfc_queue *scrq)
} }
} }
static irqreturn_t ibmvfc_interrupt_scsi(int irq, void *scrq_instance) static irqreturn_t ibmvfc_interrupt_mq(int irq, void *scrq_instance)
{ {
struct ibmvfc_queue *scrq = (struct ibmvfc_queue *)scrq_instance; struct ibmvfc_queue *scrq = (struct ibmvfc_queue *)scrq_instance;
...@@ -4031,7 +4097,13 @@ static void ibmvfc_tgt_send_prli(struct ibmvfc_target *tgt) ...@@ -4031,7 +4097,13 @@ static void ibmvfc_tgt_send_prli(struct ibmvfc_target *tgt)
return; return;
kref_get(&tgt->kref); kref_get(&tgt->kref);
evt = ibmvfc_get_event(&vhost->crq); evt = ibmvfc_get_reserved_event(&vhost->crq);
if (!evt) {
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
kref_put(&tgt->kref, ibmvfc_release_tgt);
__ibmvfc_reset_host(vhost);
return;
}
vhost->discovery_threads++; vhost->discovery_threads++;
ibmvfc_init_event(evt, ibmvfc_tgt_prli_done, IBMVFC_MAD_FORMAT); ibmvfc_init_event(evt, ibmvfc_tgt_prli_done, IBMVFC_MAD_FORMAT);
evt->tgt = tgt; evt->tgt = tgt;
...@@ -4138,7 +4210,13 @@ static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *tgt) ...@@ -4138,7 +4210,13 @@ static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *tgt)
kref_get(&tgt->kref); kref_get(&tgt->kref);
tgt->logo_rcvd = 0; tgt->logo_rcvd = 0;
evt = ibmvfc_get_event(&vhost->crq); evt = ibmvfc_get_reserved_event(&vhost->crq);
if (!evt) {
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
kref_put(&tgt->kref, ibmvfc_release_tgt);
__ibmvfc_reset_host(vhost);
return;
}
vhost->discovery_threads++; vhost->discovery_threads++;
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT);
ibmvfc_init_event(evt, ibmvfc_tgt_plogi_done, IBMVFC_MAD_FORMAT); ibmvfc_init_event(evt, ibmvfc_tgt_plogi_done, IBMVFC_MAD_FORMAT);
...@@ -4214,7 +4292,9 @@ static struct ibmvfc_event *__ibmvfc_tgt_get_implicit_logout_evt(struct ibmvfc_t ...@@ -4214,7 +4292,9 @@ static struct ibmvfc_event *__ibmvfc_tgt_get_implicit_logout_evt(struct ibmvfc_t
struct ibmvfc_event *evt; struct ibmvfc_event *evt;
kref_get(&tgt->kref); kref_get(&tgt->kref);
evt = ibmvfc_get_event(&vhost->crq); evt = ibmvfc_get_reserved_event(&vhost->crq);
if (!evt)
return NULL;
ibmvfc_init_event(evt, done, IBMVFC_MAD_FORMAT); ibmvfc_init_event(evt, done, IBMVFC_MAD_FORMAT);
evt->tgt = tgt; evt->tgt = tgt;
mad = &evt->iu.implicit_logout; mad = &evt->iu.implicit_logout;
...@@ -4242,6 +4322,13 @@ static void ibmvfc_tgt_implicit_logout(struct ibmvfc_target *tgt) ...@@ -4242,6 +4322,13 @@ static void ibmvfc_tgt_implicit_logout(struct ibmvfc_target *tgt)
vhost->discovery_threads++; vhost->discovery_threads++;
evt = __ibmvfc_tgt_get_implicit_logout_evt(tgt, evt = __ibmvfc_tgt_get_implicit_logout_evt(tgt,
ibmvfc_tgt_implicit_logout_done); ibmvfc_tgt_implicit_logout_done);
if (!evt) {
vhost->discovery_threads--;
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
kref_put(&tgt->kref, ibmvfc_release_tgt);
__ibmvfc_reset_host(vhost);
return;
}
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT);
if (ibmvfc_send_event(evt, vhost, default_timeout)) { if (ibmvfc_send_event(evt, vhost, default_timeout)) {
...@@ -4380,7 +4467,13 @@ static void ibmvfc_tgt_move_login(struct ibmvfc_target *tgt) ...@@ -4380,7 +4467,13 @@ static void ibmvfc_tgt_move_login(struct ibmvfc_target *tgt)
return; return;
kref_get(&tgt->kref); kref_get(&tgt->kref);
evt = ibmvfc_get_event(&vhost->crq); evt = ibmvfc_get_reserved_event(&vhost->crq);
if (!evt) {
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
kref_put(&tgt->kref, ibmvfc_release_tgt);
__ibmvfc_reset_host(vhost);
return;
}
vhost->discovery_threads++; vhost->discovery_threads++;
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT);
ibmvfc_init_event(evt, ibmvfc_tgt_move_login_done, IBMVFC_MAD_FORMAT); ibmvfc_init_event(evt, ibmvfc_tgt_move_login_done, IBMVFC_MAD_FORMAT);
...@@ -4546,7 +4639,15 @@ static void ibmvfc_adisc_timeout(struct timer_list *t) ...@@ -4546,7 +4639,15 @@ static void ibmvfc_adisc_timeout(struct timer_list *t)
vhost->abort_threads++; vhost->abort_threads++;
kref_get(&tgt->kref); kref_get(&tgt->kref);
evt = ibmvfc_get_event(&vhost->crq); evt = ibmvfc_get_reserved_event(&vhost->crq);
if (!evt) {
tgt_err(tgt, "Failed to get cancel event for ADISC.\n");
vhost->abort_threads--;
kref_put(&tgt->kref, ibmvfc_release_tgt);
__ibmvfc_reset_host(vhost);
spin_unlock_irqrestore(vhost->host->host_lock, flags);
return;
}
ibmvfc_init_event(evt, ibmvfc_tgt_adisc_cancel_done, IBMVFC_MAD_FORMAT); ibmvfc_init_event(evt, ibmvfc_tgt_adisc_cancel_done, IBMVFC_MAD_FORMAT);
evt->tgt = tgt; evt->tgt = tgt;
...@@ -4596,7 +4697,13 @@ static void ibmvfc_tgt_adisc(struct ibmvfc_target *tgt) ...@@ -4596,7 +4697,13 @@ static void ibmvfc_tgt_adisc(struct ibmvfc_target *tgt)
return; return;
kref_get(&tgt->kref); kref_get(&tgt->kref);
evt = ibmvfc_get_event(&vhost->crq); evt = ibmvfc_get_reserved_event(&vhost->crq);
if (!evt) {
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
kref_put(&tgt->kref, ibmvfc_release_tgt);
__ibmvfc_reset_host(vhost);
return;
}
vhost->discovery_threads++; vhost->discovery_threads++;
ibmvfc_init_event(evt, ibmvfc_tgt_adisc_done, IBMVFC_MAD_FORMAT); ibmvfc_init_event(evt, ibmvfc_tgt_adisc_done, IBMVFC_MAD_FORMAT);
evt->tgt = tgt; evt->tgt = tgt;
...@@ -4699,7 +4806,13 @@ static void ibmvfc_tgt_query_target(struct ibmvfc_target *tgt) ...@@ -4699,7 +4806,13 @@ static void ibmvfc_tgt_query_target(struct ibmvfc_target *tgt)
return; return;
kref_get(&tgt->kref); kref_get(&tgt->kref);
evt = ibmvfc_get_event(&vhost->crq); evt = ibmvfc_get_reserved_event(&vhost->crq);
if (!evt) {
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
kref_put(&tgt->kref, ibmvfc_release_tgt);
__ibmvfc_reset_host(vhost);
return;
}
vhost->discovery_threads++; vhost->discovery_threads++;
evt->tgt = tgt; evt->tgt = tgt;
ibmvfc_init_event(evt, ibmvfc_tgt_query_target_done, IBMVFC_MAD_FORMAT); ibmvfc_init_event(evt, ibmvfc_tgt_query_target_done, IBMVFC_MAD_FORMAT);
...@@ -4822,7 +4935,7 @@ static int ibmvfc_alloc_targets(struct ibmvfc_host *vhost) ...@@ -4822,7 +4935,7 @@ static int ibmvfc_alloc_targets(struct ibmvfc_host *vhost)
int i, rc; int i, rc;
for (i = 0, rc = 0; !rc && i < vhost->num_targets; i++) for (i = 0, rc = 0; !rc && i < vhost->num_targets; i++)
rc = ibmvfc_alloc_target(vhost, &vhost->disc_buf[i]); rc = ibmvfc_alloc_target(vhost, &vhost->scsi_scrqs.disc_buf[i]);
return rc; return rc;
} }
...@@ -4871,7 +4984,14 @@ static void ibmvfc_discover_targets_done(struct ibmvfc_event *evt) ...@@ -4871,7 +4984,14 @@ static void ibmvfc_discover_targets_done(struct ibmvfc_event *evt)
static void ibmvfc_discover_targets(struct ibmvfc_host *vhost) static void ibmvfc_discover_targets(struct ibmvfc_host *vhost)
{ {
struct ibmvfc_discover_targets *mad; struct ibmvfc_discover_targets *mad;
struct ibmvfc_event *evt = ibmvfc_get_event(&vhost->crq); struct ibmvfc_event *evt = ibmvfc_get_reserved_event(&vhost->crq);
int level = IBMVFC_DEFAULT_LOG_LEVEL;
if (!evt) {
ibmvfc_log(vhost, level, "Discover Targets failed: no available events\n");
ibmvfc_hard_reset_host(vhost);
return;
}
ibmvfc_init_event(evt, ibmvfc_discover_targets_done, IBMVFC_MAD_FORMAT); ibmvfc_init_event(evt, ibmvfc_discover_targets_done, IBMVFC_MAD_FORMAT);
mad = &evt->iu.discover_targets; mad = &evt->iu.discover_targets;
...@@ -4879,9 +4999,9 @@ static void ibmvfc_discover_targets(struct ibmvfc_host *vhost) ...@@ -4879,9 +4999,9 @@ static void ibmvfc_discover_targets(struct ibmvfc_host *vhost)
mad->common.version = cpu_to_be32(1); mad->common.version = cpu_to_be32(1);
mad->common.opcode = cpu_to_be32(IBMVFC_DISC_TARGETS); mad->common.opcode = cpu_to_be32(IBMVFC_DISC_TARGETS);
mad->common.length = cpu_to_be16(sizeof(*mad)); mad->common.length = cpu_to_be16(sizeof(*mad));
mad->bufflen = cpu_to_be32(vhost->disc_buf_sz); mad->bufflen = cpu_to_be32(vhost->scsi_scrqs.disc_buf_sz);
mad->buffer.va = cpu_to_be64(vhost->disc_buf_dma); mad->buffer.va = cpu_to_be64(vhost->scsi_scrqs.disc_buf_dma);
mad->buffer.len = cpu_to_be32(vhost->disc_buf_sz); mad->buffer.len = cpu_to_be32(vhost->scsi_scrqs.disc_buf_sz);
mad->flags = cpu_to_be32(IBMVFC_DISC_TGT_PORT_ID_WWPN_LIST); mad->flags = cpu_to_be32(IBMVFC_DISC_TGT_PORT_ID_WWPN_LIST);
ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT_WAIT); ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT_WAIT);
...@@ -4895,7 +5015,7 @@ static void ibmvfc_channel_setup_done(struct ibmvfc_event *evt) ...@@ -4895,7 +5015,7 @@ static void ibmvfc_channel_setup_done(struct ibmvfc_event *evt)
{ {
struct ibmvfc_host *vhost = evt->vhost; struct ibmvfc_host *vhost = evt->vhost;
struct ibmvfc_channel_setup *setup = vhost->channel_setup_buf; struct ibmvfc_channel_setup *setup = vhost->channel_setup_buf;
struct ibmvfc_scsi_channels *scrqs = &vhost->scsi_scrqs; struct ibmvfc_channels *scrqs = &vhost->scsi_scrqs;
u32 mad_status = be16_to_cpu(evt->xfer_iu->channel_setup.common.status); u32 mad_status = be16_to_cpu(evt->xfer_iu->channel_setup.common.status);
int level = IBMVFC_DEFAULT_LOG_LEVEL; int level = IBMVFC_DEFAULT_LOG_LEVEL;
int flags, active_queues, i; int flags, active_queues, i;
...@@ -4945,12 +5065,19 @@ static void ibmvfc_channel_setup(struct ibmvfc_host *vhost) ...@@ -4945,12 +5065,19 @@ static void ibmvfc_channel_setup(struct ibmvfc_host *vhost)
{ {
struct ibmvfc_channel_setup_mad *mad; struct ibmvfc_channel_setup_mad *mad;
struct ibmvfc_channel_setup *setup_buf = vhost->channel_setup_buf; struct ibmvfc_channel_setup *setup_buf = vhost->channel_setup_buf;
struct ibmvfc_event *evt = ibmvfc_get_event(&vhost->crq); struct ibmvfc_event *evt = ibmvfc_get_reserved_event(&vhost->crq);
struct ibmvfc_scsi_channels *scrqs = &vhost->scsi_scrqs; struct ibmvfc_channels *scrqs = &vhost->scsi_scrqs;
unsigned int num_channels = unsigned int num_channels =
min(vhost->client_scsi_channels, vhost->max_vios_scsi_channels); min(scrqs->desired_queues, vhost->max_vios_scsi_channels);
int level = IBMVFC_DEFAULT_LOG_LEVEL;
int i; int i;
if (!evt) {
ibmvfc_log(vhost, level, "Channel Setup failed: no available events\n");
ibmvfc_hard_reset_host(vhost);
return;
}
memset(setup_buf, 0, sizeof(*setup_buf)); memset(setup_buf, 0, sizeof(*setup_buf));
if (num_channels == 0) if (num_channels == 0)
setup_buf->flags = cpu_to_be32(IBMVFC_CANCEL_CHANNELS); setup_buf->flags = cpu_to_be32(IBMVFC_CANCEL_CHANNELS);
...@@ -5011,7 +5138,14 @@ static void ibmvfc_channel_enquiry_done(struct ibmvfc_event *evt) ...@@ -5011,7 +5138,14 @@ static void ibmvfc_channel_enquiry_done(struct ibmvfc_event *evt)
static void ibmvfc_channel_enquiry(struct ibmvfc_host *vhost) static void ibmvfc_channel_enquiry(struct ibmvfc_host *vhost)
{ {
struct ibmvfc_channel_enquiry *mad; struct ibmvfc_channel_enquiry *mad;
struct ibmvfc_event *evt = ibmvfc_get_event(&vhost->crq); struct ibmvfc_event *evt = ibmvfc_get_reserved_event(&vhost->crq);
int level = IBMVFC_DEFAULT_LOG_LEVEL;
if (!evt) {
ibmvfc_log(vhost, level, "Channel Enquiry failed: no available events\n");
ibmvfc_hard_reset_host(vhost);
return;
}
ibmvfc_init_event(evt, ibmvfc_channel_enquiry_done, IBMVFC_MAD_FORMAT); ibmvfc_init_event(evt, ibmvfc_channel_enquiry_done, IBMVFC_MAD_FORMAT);
mad = &evt->iu.channel_enquiry; mad = &evt->iu.channel_enquiry;
...@@ -5132,7 +5266,13 @@ static void ibmvfc_npiv_login_done(struct ibmvfc_event *evt) ...@@ -5132,7 +5266,13 @@ static void ibmvfc_npiv_login_done(struct ibmvfc_event *evt)
static void ibmvfc_npiv_login(struct ibmvfc_host *vhost) static void ibmvfc_npiv_login(struct ibmvfc_host *vhost)
{ {
struct ibmvfc_npiv_login_mad *mad; struct ibmvfc_npiv_login_mad *mad;
struct ibmvfc_event *evt = ibmvfc_get_event(&vhost->crq); struct ibmvfc_event *evt = ibmvfc_get_reserved_event(&vhost->crq);
if (!evt) {
ibmvfc_dbg(vhost, "NPIV Login failed: no available events\n");
ibmvfc_hard_reset_host(vhost);
return;
}
ibmvfc_gather_partition_info(vhost); ibmvfc_gather_partition_info(vhost);
ibmvfc_set_login_info(vhost); ibmvfc_set_login_info(vhost);
...@@ -5197,7 +5337,13 @@ static void ibmvfc_npiv_logout(struct ibmvfc_host *vhost) ...@@ -5197,7 +5337,13 @@ static void ibmvfc_npiv_logout(struct ibmvfc_host *vhost)
struct ibmvfc_npiv_logout_mad *mad; struct ibmvfc_npiv_logout_mad *mad;
struct ibmvfc_event *evt; struct ibmvfc_event *evt;
evt = ibmvfc_get_event(&vhost->crq); evt = ibmvfc_get_reserved_event(&vhost->crq);
if (!evt) {
ibmvfc_dbg(vhost, "NPIV Logout failed: no available events\n");
ibmvfc_hard_reset_host(vhost);
return;
}
ibmvfc_init_event(evt, ibmvfc_npiv_logout_done, IBMVFC_MAD_FORMAT); ibmvfc_init_event(evt, ibmvfc_npiv_logout_done, IBMVFC_MAD_FORMAT);
mad = &evt->iu.npiv_logout; mad = &evt->iu.npiv_logout;
...@@ -5645,7 +5791,6 @@ static int ibmvfc_alloc_queue(struct ibmvfc_host *vhost, ...@@ -5645,7 +5791,6 @@ static int ibmvfc_alloc_queue(struct ibmvfc_host *vhost,
{ {
struct device *dev = vhost->dev; struct device *dev = vhost->dev;
size_t fmt_size; size_t fmt_size;
unsigned int pool_size = 0;
ENTER; ENTER;
spin_lock_init(&queue->_lock); spin_lock_init(&queue->_lock);
...@@ -5654,7 +5799,9 @@ static int ibmvfc_alloc_queue(struct ibmvfc_host *vhost, ...@@ -5654,7 +5799,9 @@ static int ibmvfc_alloc_queue(struct ibmvfc_host *vhost,
switch (fmt) { switch (fmt) {
case IBMVFC_CRQ_FMT: case IBMVFC_CRQ_FMT:
fmt_size = sizeof(*queue->msgs.crq); fmt_size = sizeof(*queue->msgs.crq);
pool_size = max_requests + IBMVFC_NUM_INTERNAL_REQ; queue->total_depth = scsi_qdepth + IBMVFC_NUM_INTERNAL_REQ;
queue->evt_depth = scsi_qdepth;
queue->reserved_depth = IBMVFC_NUM_INTERNAL_REQ;
break; break;
case IBMVFC_ASYNC_FMT: case IBMVFC_ASYNC_FMT:
fmt_size = sizeof(*queue->msgs.async); fmt_size = sizeof(*queue->msgs.async);
...@@ -5662,14 +5809,17 @@ static int ibmvfc_alloc_queue(struct ibmvfc_host *vhost, ...@@ -5662,14 +5809,17 @@ static int ibmvfc_alloc_queue(struct ibmvfc_host *vhost,
case IBMVFC_SUB_CRQ_FMT: case IBMVFC_SUB_CRQ_FMT:
fmt_size = sizeof(*queue->msgs.scrq); fmt_size = sizeof(*queue->msgs.scrq);
/* We need one extra event for Cancel Commands */ /* We need one extra event for Cancel Commands */
pool_size = max_requests + 1; queue->total_depth = scsi_qdepth + IBMVFC_NUM_INTERNAL_SUBQ_REQ;
queue->evt_depth = scsi_qdepth;
queue->reserved_depth = IBMVFC_NUM_INTERNAL_SUBQ_REQ;
break; break;
default: default:
dev_warn(dev, "Unknown command/response queue message format: %d\n", fmt); dev_warn(dev, "Unknown command/response queue message format: %d\n", fmt);
return -EINVAL; return -EINVAL;
} }
if (ibmvfc_init_event_pool(vhost, queue, pool_size)) { queue->fmt = fmt;
if (ibmvfc_init_event_pool(vhost, queue)) {
dev_err(dev, "Couldn't initialize event pool.\n"); dev_err(dev, "Couldn't initialize event pool.\n");
return -ENOMEM; return -ENOMEM;
} }
...@@ -5688,7 +5838,6 @@ static int ibmvfc_alloc_queue(struct ibmvfc_host *vhost, ...@@ -5688,7 +5838,6 @@ static int ibmvfc_alloc_queue(struct ibmvfc_host *vhost,
} }
queue->cur = 0; queue->cur = 0;
queue->fmt = fmt;
queue->size = PAGE_SIZE / fmt_size; queue->size = PAGE_SIZE / fmt_size;
queue->vhost = vhost; queue->vhost = vhost;
...@@ -5757,12 +5906,13 @@ static int ibmvfc_init_crq(struct ibmvfc_host *vhost) ...@@ -5757,12 +5906,13 @@ static int ibmvfc_init_crq(struct ibmvfc_host *vhost)
return retrc; return retrc;
} }
static int ibmvfc_register_scsi_channel(struct ibmvfc_host *vhost, static int ibmvfc_register_channel(struct ibmvfc_host *vhost,
int index) struct ibmvfc_channels *channels,
int index)
{ {
struct device *dev = vhost->dev; struct device *dev = vhost->dev;
struct vio_dev *vdev = to_vio_dev(dev); struct vio_dev *vdev = to_vio_dev(dev);
struct ibmvfc_queue *scrq = &vhost->scsi_scrqs.scrqs[index]; struct ibmvfc_queue *scrq = &channels->scrqs[index];
int rc = -ENOMEM; int rc = -ENOMEM;
ENTER; ENTER;
...@@ -5786,9 +5936,24 @@ static int ibmvfc_register_scsi_channel(struct ibmvfc_host *vhost, ...@@ -5786,9 +5936,24 @@ static int ibmvfc_register_scsi_channel(struct ibmvfc_host *vhost,
goto irq_failed; goto irq_failed;
} }
snprintf(scrq->name, sizeof(scrq->name), "ibmvfc-%x-scsi%d", switch (channels->protocol) {
vdev->unit_address, index); case IBMVFC_PROTO_SCSI:
rc = request_irq(scrq->irq, ibmvfc_interrupt_scsi, 0, scrq->name, scrq); snprintf(scrq->name, sizeof(scrq->name), "ibmvfc-%x-scsi%d",
vdev->unit_address, index);
scrq->handler = ibmvfc_interrupt_mq;
break;
case IBMVFC_PROTO_NVME:
snprintf(scrq->name, sizeof(scrq->name), "ibmvfc-%x-nvmf%d",
vdev->unit_address, index);
scrq->handler = ibmvfc_interrupt_mq;
break;
default:
dev_err(dev, "Unknown channel protocol (%d)\n",
channels->protocol);
goto irq_failed;
}
rc = request_irq(scrq->irq, scrq->handler, 0, scrq->name, scrq);
if (rc) { if (rc) {
dev_err(dev, "Couldn't register sub-crq[%d] irq\n", index); dev_err(dev, "Couldn't register sub-crq[%d] irq\n", index);
...@@ -5804,17 +5969,19 @@ static int ibmvfc_register_scsi_channel(struct ibmvfc_host *vhost, ...@@ -5804,17 +5969,19 @@ static int ibmvfc_register_scsi_channel(struct ibmvfc_host *vhost,
irq_failed: irq_failed:
do { do {
rc = plpar_hcall_norets(H_FREE_SUB_CRQ, vdev->unit_address, scrq->cookie); rc = plpar_hcall_norets(H_FREE_SUB_CRQ, vdev->unit_address, scrq->cookie);
} while (rtas_busy_delay(rc)); } while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
reg_failed: reg_failed:
LEAVE; LEAVE;
return rc; return rc;
} }
static void ibmvfc_deregister_scsi_channel(struct ibmvfc_host *vhost, int index) static void ibmvfc_deregister_channel(struct ibmvfc_host *vhost,
struct ibmvfc_channels *channels,
int index)
{ {
struct device *dev = vhost->dev; struct device *dev = vhost->dev;
struct vio_dev *vdev = to_vio_dev(dev); struct vio_dev *vdev = to_vio_dev(dev);
struct ibmvfc_queue *scrq = &vhost->scsi_scrqs.scrqs[index]; struct ibmvfc_queue *scrq = &channels->scrqs[index];
long rc; long rc;
ENTER; ENTER;
...@@ -5838,18 +6005,19 @@ static void ibmvfc_deregister_scsi_channel(struct ibmvfc_host *vhost, int index) ...@@ -5838,18 +6005,19 @@ static void ibmvfc_deregister_scsi_channel(struct ibmvfc_host *vhost, int index)
LEAVE; LEAVE;
} }
static void ibmvfc_reg_sub_crqs(struct ibmvfc_host *vhost) static void ibmvfc_reg_sub_crqs(struct ibmvfc_host *vhost,
struct ibmvfc_channels *channels)
{ {
int i, j; int i, j;
ENTER; ENTER;
if (!vhost->mq_enabled || !vhost->scsi_scrqs.scrqs) if (!vhost->mq_enabled || !channels->scrqs)
return; return;
for (i = 0; i < nr_scsi_hw_queues; i++) { for (i = 0; i < channels->max_queues; i++) {
if (ibmvfc_register_scsi_channel(vhost, i)) { if (ibmvfc_register_channel(vhost, channels, i)) {
for (j = i; j > 0; j--) for (j = i; j > 0; j--)
ibmvfc_deregister_scsi_channel(vhost, j - 1); ibmvfc_deregister_channel(vhost, channels, j - 1);
vhost->do_enquiry = 0; vhost->do_enquiry = 0;
return; return;
} }
...@@ -5858,80 +6026,105 @@ static void ibmvfc_reg_sub_crqs(struct ibmvfc_host *vhost) ...@@ -5858,80 +6026,105 @@ static void ibmvfc_reg_sub_crqs(struct ibmvfc_host *vhost)
LEAVE; LEAVE;
} }
static void ibmvfc_dereg_sub_crqs(struct ibmvfc_host *vhost) static void ibmvfc_dereg_sub_crqs(struct ibmvfc_host *vhost,
struct ibmvfc_channels *channels)
{ {
int i; int i;
ENTER; ENTER;
if (!vhost->mq_enabled || !vhost->scsi_scrqs.scrqs) if (!vhost->mq_enabled || !channels->scrqs)
return; return;
for (i = 0; i < nr_scsi_hw_queues; i++) for (i = 0; i < channels->max_queues; i++)
ibmvfc_deregister_scsi_channel(vhost, i); ibmvfc_deregister_channel(vhost, channels, i);
LEAVE; LEAVE;
} }
static void ibmvfc_init_sub_crqs(struct ibmvfc_host *vhost) static int ibmvfc_alloc_channels(struct ibmvfc_host *vhost,
struct ibmvfc_channels *channels)
{ {
struct ibmvfc_queue *scrq; struct ibmvfc_queue *scrq;
int i, j; int i, j;
int rc = 0;
channels->scrqs = kcalloc(channels->max_queues,
sizeof(*channels->scrqs),
GFP_KERNEL);
if (!channels->scrqs)
return -ENOMEM;
for (i = 0; i < channels->max_queues; i++) {
scrq = &channels->scrqs[i];
rc = ibmvfc_alloc_queue(vhost, scrq, IBMVFC_SUB_CRQ_FMT);
if (rc) {
for (j = i; j > 0; j--) {
scrq = &channels->scrqs[j - 1];
ibmvfc_free_queue(vhost, scrq);
}
kfree(channels->scrqs);
channels->scrqs = NULL;
channels->active_queues = 0;
return rc;
}
}
return rc;
}
static void ibmvfc_init_sub_crqs(struct ibmvfc_host *vhost)
{
ENTER; ENTER;
if (!vhost->mq_enabled) if (!vhost->mq_enabled)
return; return;
vhost->scsi_scrqs.scrqs = kcalloc(nr_scsi_hw_queues, if (ibmvfc_alloc_channels(vhost, &vhost->scsi_scrqs)) {
sizeof(*vhost->scsi_scrqs.scrqs),
GFP_KERNEL);
if (!vhost->scsi_scrqs.scrqs) {
vhost->do_enquiry = 0; vhost->do_enquiry = 0;
vhost->mq_enabled = 0;
return; return;
} }
for (i = 0; i < nr_scsi_hw_queues; i++) { ibmvfc_reg_sub_crqs(vhost, &vhost->scsi_scrqs);
scrq = &vhost->scsi_scrqs.scrqs[i];
if (ibmvfc_alloc_queue(vhost, scrq, IBMVFC_SUB_CRQ_FMT)) {
for (j = i; j > 0; j--) {
scrq = &vhost->scsi_scrqs.scrqs[j - 1];
ibmvfc_free_queue(vhost, scrq);
}
kfree(vhost->scsi_scrqs.scrqs);
vhost->scsi_scrqs.scrqs = NULL;
vhost->scsi_scrqs.active_queues = 0;
vhost->do_enquiry = 0;
vhost->mq_enabled = 0;
return;
}
}
ibmvfc_reg_sub_crqs(vhost);
LEAVE; LEAVE;
} }
static void ibmvfc_release_sub_crqs(struct ibmvfc_host *vhost) static void ibmvfc_release_channels(struct ibmvfc_host *vhost,
struct ibmvfc_channels *channels)
{ {
struct ibmvfc_queue *scrq; struct ibmvfc_queue *scrq;
int i; int i;
if (channels->scrqs) {
for (i = 0; i < channels->max_queues; i++) {
scrq = &channels->scrqs[i];
ibmvfc_free_queue(vhost, scrq);
}
kfree(channels->scrqs);
channels->scrqs = NULL;
channels->active_queues = 0;
}
}
static void ibmvfc_release_sub_crqs(struct ibmvfc_host *vhost)
{
ENTER; ENTER;
if (!vhost->scsi_scrqs.scrqs) if (!vhost->scsi_scrqs.scrqs)
return; return;
ibmvfc_dereg_sub_crqs(vhost); ibmvfc_dereg_sub_crqs(vhost, &vhost->scsi_scrqs);
for (i = 0; i < nr_scsi_hw_queues; i++) {
scrq = &vhost->scsi_scrqs.scrqs[i];
ibmvfc_free_queue(vhost, scrq);
}
kfree(vhost->scsi_scrqs.scrqs); ibmvfc_release_channels(vhost, &vhost->scsi_scrqs);
vhost->scsi_scrqs.scrqs = NULL;
vhost->scsi_scrqs.active_queues = 0;
LEAVE; LEAVE;
} }
static void ibmvfc_free_disc_buf(struct device *dev, struct ibmvfc_channels *channels)
{
dma_free_coherent(dev, channels->disc_buf_sz, channels->disc_buf,
channels->disc_buf_dma);
}
/** /**
* ibmvfc_free_mem - Free memory for vhost * ibmvfc_free_mem - Free memory for vhost
* @vhost: ibmvfc host struct * @vhost: ibmvfc host struct
...@@ -5946,8 +6139,7 @@ static void ibmvfc_free_mem(struct ibmvfc_host *vhost) ...@@ -5946,8 +6139,7 @@ static void ibmvfc_free_mem(struct ibmvfc_host *vhost)
ENTER; ENTER;
mempool_destroy(vhost->tgt_pool); mempool_destroy(vhost->tgt_pool);
kfree(vhost->trace); kfree(vhost->trace);
dma_free_coherent(vhost->dev, vhost->disc_buf_sz, vhost->disc_buf, ibmvfc_free_disc_buf(vhost->dev, &vhost->scsi_scrqs);
vhost->disc_buf_dma);
dma_free_coherent(vhost->dev, sizeof(*vhost->login_buf), dma_free_coherent(vhost->dev, sizeof(*vhost->login_buf),
vhost->login_buf, vhost->login_buf_dma); vhost->login_buf, vhost->login_buf_dma);
dma_free_coherent(vhost->dev, sizeof(*vhost->channel_setup_buf), dma_free_coherent(vhost->dev, sizeof(*vhost->channel_setup_buf),
...@@ -5957,6 +6149,21 @@ static void ibmvfc_free_mem(struct ibmvfc_host *vhost) ...@@ -5957,6 +6149,21 @@ static void ibmvfc_free_mem(struct ibmvfc_host *vhost)
LEAVE; LEAVE;
} }
static int ibmvfc_alloc_disc_buf(struct device *dev, struct ibmvfc_channels *channels)
{
channels->disc_buf_sz = sizeof(*channels->disc_buf) * max_targets;
channels->disc_buf = dma_alloc_coherent(dev, channels->disc_buf_sz,
&channels->disc_buf_dma, GFP_KERNEL);
if (!channels->disc_buf) {
dev_err(dev, "Couldn't allocate %s Discover Targets buffer\n",
(channels->protocol == IBMVFC_PROTO_SCSI) ? "SCSI" : "NVMe");
return -ENOMEM;
}
return 0;
}
/** /**
* ibmvfc_alloc_mem - Allocate memory for vhost * ibmvfc_alloc_mem - Allocate memory for vhost
* @vhost: ibmvfc host struct * @vhost: ibmvfc host struct
...@@ -5992,21 +6199,15 @@ static int ibmvfc_alloc_mem(struct ibmvfc_host *vhost) ...@@ -5992,21 +6199,15 @@ static int ibmvfc_alloc_mem(struct ibmvfc_host *vhost)
goto free_sg_pool; goto free_sg_pool;
} }
vhost->disc_buf_sz = sizeof(*vhost->disc_buf) * max_targets; if (ibmvfc_alloc_disc_buf(dev, &vhost->scsi_scrqs))
vhost->disc_buf = dma_alloc_coherent(dev, vhost->disc_buf_sz,
&vhost->disc_buf_dma, GFP_KERNEL);
if (!vhost->disc_buf) {
dev_err(dev, "Couldn't allocate Discover Targets buffer\n");
goto free_login_buffer; goto free_login_buffer;
}
vhost->trace = kcalloc(IBMVFC_NUM_TRACE_ENTRIES, vhost->trace = kcalloc(IBMVFC_NUM_TRACE_ENTRIES,
sizeof(struct ibmvfc_trace_entry), GFP_KERNEL); sizeof(struct ibmvfc_trace_entry), GFP_KERNEL);
atomic_set(&vhost->trace_index, -1); atomic_set(&vhost->trace_index, -1);
if (!vhost->trace) if (!vhost->trace)
goto free_disc_buffer; goto free_scsi_disc_buffer;
vhost->tgt_pool = mempool_create_kmalloc_pool(IBMVFC_TGT_MEMPOOL_SZ, vhost->tgt_pool = mempool_create_kmalloc_pool(IBMVFC_TGT_MEMPOOL_SZ,
sizeof(struct ibmvfc_target)); sizeof(struct ibmvfc_target));
...@@ -6032,9 +6233,8 @@ static int ibmvfc_alloc_mem(struct ibmvfc_host *vhost) ...@@ -6032,9 +6233,8 @@ static int ibmvfc_alloc_mem(struct ibmvfc_host *vhost)
mempool_destroy(vhost->tgt_pool); mempool_destroy(vhost->tgt_pool);
free_trace: free_trace:
kfree(vhost->trace); kfree(vhost->trace);
free_disc_buffer: free_scsi_disc_buffer:
dma_free_coherent(dev, vhost->disc_buf_sz, vhost->disc_buf, ibmvfc_free_disc_buf(dev, &vhost->scsi_scrqs);
vhost->disc_buf_dma);
free_login_buffer: free_login_buffer:
dma_free_coherent(dev, sizeof(*vhost->login_buf), dma_free_coherent(dev, sizeof(*vhost->login_buf),
vhost->login_buf, vhost->login_buf_dma); vhost->login_buf, vhost->login_buf_dma);
...@@ -6113,7 +6313,8 @@ static int ibmvfc_probe(struct vio_dev *vdev, const struct vio_device_id *id) ...@@ -6113,7 +6313,8 @@ static int ibmvfc_probe(struct vio_dev *vdev, const struct vio_device_id *id)
struct Scsi_Host *shost; struct Scsi_Host *shost;
struct device *dev = &vdev->dev; struct device *dev = &vdev->dev;
int rc = -ENOMEM; int rc = -ENOMEM;
unsigned int max_scsi_queues = IBMVFC_MAX_SCSI_QUEUES; unsigned int online_cpus = num_online_cpus();
unsigned int max_scsi_queues = min((unsigned int)IBMVFC_MAX_SCSI_QUEUES, online_cpus);
ENTER; ENTER;
shost = scsi_host_alloc(&driver_template, sizeof(*vhost)); shost = scsi_host_alloc(&driver_template, sizeof(*vhost));
...@@ -6123,7 +6324,7 @@ static int ibmvfc_probe(struct vio_dev *vdev, const struct vio_device_id *id) ...@@ -6123,7 +6324,7 @@ static int ibmvfc_probe(struct vio_dev *vdev, const struct vio_device_id *id)
} }
shost->transportt = ibmvfc_transport_template; shost->transportt = ibmvfc_transport_template;
shost->can_queue = max_requests; shost->can_queue = scsi_qdepth;
shost->max_lun = max_lun; shost->max_lun = max_lun;
shost->max_id = max_targets; shost->max_id = max_targets;
shost->max_sectors = IBMVFC_MAX_SECTORS; shost->max_sectors = IBMVFC_MAX_SECTORS;
...@@ -6142,7 +6343,9 @@ static int ibmvfc_probe(struct vio_dev *vdev, const struct vio_device_id *id) ...@@ -6142,7 +6343,9 @@ static int ibmvfc_probe(struct vio_dev *vdev, const struct vio_device_id *id)
vhost->task_set = 1; vhost->task_set = 1;
vhost->mq_enabled = mq_enabled; vhost->mq_enabled = mq_enabled;
vhost->client_scsi_channels = min(shost->nr_hw_queues, nr_scsi_channels); vhost->scsi_scrqs.desired_queues = min(shost->nr_hw_queues, nr_scsi_channels);
vhost->scsi_scrqs.max_queues = shost->nr_hw_queues;
vhost->scsi_scrqs.protocol = IBMVFC_PROTO_SCSI;
vhost->using_channels = 0; vhost->using_channels = 0;
vhost->do_enquiry = 1; vhost->do_enquiry = 1;
vhost->scan_timeout = 0; vhost->scan_timeout = 0;
...@@ -6282,7 +6485,9 @@ static int ibmvfc_resume(struct device *dev) ...@@ -6282,7 +6485,9 @@ static int ibmvfc_resume(struct device *dev)
*/ */
static unsigned long ibmvfc_get_desired_dma(struct vio_dev *vdev) static unsigned long ibmvfc_get_desired_dma(struct vio_dev *vdev)
{ {
unsigned long pool_dma = max_requests * sizeof(union ibmvfc_iu); unsigned long pool_dma;
pool_dma = (IBMVFC_MAX_SCSI_QUEUES * scsi_qdepth) * sizeof(union ibmvfc_iu);
return pool_dma + ((512 * 1024) * driver_template.cmd_per_lun); return pool_dma + ((512 * 1024) * driver_template.cmd_per_lun);
} }
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#define IBMVFC_ABORT_TIMEOUT 8 #define IBMVFC_ABORT_TIMEOUT 8
#define IBMVFC_ABORT_WAIT_TIMEOUT 40 #define IBMVFC_ABORT_WAIT_TIMEOUT 40
#define IBMVFC_MAX_REQUESTS_DEFAULT 100 #define IBMVFC_MAX_REQUESTS_DEFAULT 100
#define IBMVFC_SCSI_QDEPTH 128
#define IBMVFC_DEBUG 0 #define IBMVFC_DEBUG 0
#define IBMVFC_MAX_TARGETS 1024 #define IBMVFC_MAX_TARGETS 1024
...@@ -57,6 +58,8 @@ ...@@ -57,6 +58,8 @@
* 2 for each discovery thread * 2 for each discovery thread
*/ */
#define IBMVFC_NUM_INTERNAL_REQ (1 + 1 + 1 + 2 + (disc_threads * 2)) #define IBMVFC_NUM_INTERNAL_REQ (1 + 1 + 1 + 2 + (disc_threads * 2))
/* Reserved suset of events for cancelling channelized IO commands */
#define IBMVFC_NUM_INTERNAL_SUBQ_REQ 4
#define IBMVFC_MAD_SUCCESS 0x00 #define IBMVFC_MAD_SUCCESS 0x00
#define IBMVFC_MAD_NOT_SUPPORTED 0xF1 #define IBMVFC_MAD_NOT_SUPPORTED 0xF1
...@@ -713,9 +716,15 @@ enum ibmvfc_target_action { ...@@ -713,9 +716,15 @@ enum ibmvfc_target_action {
IBMVFC_TGT_ACTION_LOGOUT_DELETED_RPORT, IBMVFC_TGT_ACTION_LOGOUT_DELETED_RPORT,
}; };
enum ibmvfc_protocol {
IBMVFC_PROTO_SCSI = 0,
IBMVFC_PROTO_NVME = 1,
};
struct ibmvfc_target { struct ibmvfc_target {
struct list_head queue; struct list_head queue;
struct ibmvfc_host *vhost; struct ibmvfc_host *vhost;
enum ibmvfc_protocol protocol;
u64 scsi_id; u64 scsi_id;
u64 wwpn; u64 wwpn;
u64 new_scsi_id; u64 new_scsi_id;
...@@ -758,6 +767,7 @@ struct ibmvfc_event { ...@@ -758,6 +767,7 @@ struct ibmvfc_event {
struct completion *eh_comp; struct completion *eh_comp;
struct timer_list timer; struct timer_list timer;
u16 hwq; u16 hwq;
u8 reserved;
}; };
/* a pool of event structs for use */ /* a pool of event structs for use */
...@@ -793,6 +803,11 @@ struct ibmvfc_queue { ...@@ -793,6 +803,11 @@ struct ibmvfc_queue {
struct ibmvfc_event_pool evt_pool; struct ibmvfc_event_pool evt_pool;
struct list_head sent; struct list_head sent;
struct list_head free; struct list_head free;
u16 total_depth;
u16 evt_depth;
u16 reserved_depth;
u16 evt_free;
u16 reserved_free;
spinlock_t l_lock; spinlock_t l_lock;
union ibmvfc_iu cancel_rsp; union ibmvfc_iu cancel_rsp;
...@@ -804,11 +819,18 @@ struct ibmvfc_queue { ...@@ -804,11 +819,18 @@ struct ibmvfc_queue {
unsigned long irq; unsigned long irq;
unsigned long hwq_id; unsigned long hwq_id;
char name[32]; char name[32];
irq_handler_t handler;
}; };
struct ibmvfc_scsi_channels { struct ibmvfc_channels {
struct ibmvfc_queue *scrqs; struct ibmvfc_queue *scrqs;
enum ibmvfc_protocol protocol;
unsigned int active_queues; unsigned int active_queues;
unsigned int desired_queues;
unsigned int max_queues;
int disc_buf_sz;
struct ibmvfc_discover_targets_entry *disc_buf;
dma_addr_t disc_buf_dma;
}; };
enum ibmvfc_host_action { enum ibmvfc_host_action {
...@@ -857,37 +879,33 @@ struct ibmvfc_host { ...@@ -857,37 +879,33 @@ struct ibmvfc_host {
mempool_t *tgt_pool; mempool_t *tgt_pool;
struct ibmvfc_queue crq; struct ibmvfc_queue crq;
struct ibmvfc_queue async_crq; struct ibmvfc_queue async_crq;
struct ibmvfc_scsi_channels scsi_scrqs; struct ibmvfc_channels scsi_scrqs;
struct ibmvfc_npiv_login login_info; struct ibmvfc_npiv_login login_info;
union ibmvfc_npiv_login_data *login_buf; union ibmvfc_npiv_login_data *login_buf;
dma_addr_t login_buf_dma; dma_addr_t login_buf_dma;
struct ibmvfc_channel_setup *channel_setup_buf; struct ibmvfc_channel_setup *channel_setup_buf;
dma_addr_t channel_setup_dma; dma_addr_t channel_setup_dma;
int disc_buf_sz;
int log_level; int log_level;
struct ibmvfc_discover_targets_entry *disc_buf;
struct mutex passthru_mutex; struct mutex passthru_mutex;
int max_vios_scsi_channels; unsigned int max_vios_scsi_channels;
int task_set; int task_set;
int init_retries; int init_retries;
int discovery_threads; int discovery_threads;
int abort_threads; int abort_threads;
int client_migrated; int client_migrated:1;
int reinit; int reinit:1;
int delay_init; int delay_init:1;
int scan_complete; int logged_in:1;
int mq_enabled:1;
int using_channels:1;
int do_enquiry:1;
int aborting_passthru:1;
int scan_complete:1;
int scan_timeout; int scan_timeout;
int logged_in;
int mq_enabled;
int using_channels;
int do_enquiry;
int client_scsi_channels;
int aborting_passthru;
int events_to_log; int events_to_log;
#define IBMVFC_AE_LINKUP 0x0001 #define IBMVFC_AE_LINKUP 0x0001
#define IBMVFC_AE_LINKDOWN 0x0002 #define IBMVFC_AE_LINKDOWN 0x0002
#define IBMVFC_AE_RSCN 0x0004 #define IBMVFC_AE_RSCN 0x0004
dma_addr_t disc_buf_dma;
unsigned int partition_number; unsigned int partition_number;
char partition_name[97]; char partition_name[97];
void (*job_step) (struct ibmvfc_host *); void (*job_step) (struct ibmvfc_host *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment