Merge branch 'nvme-4.13' of git://git.infradead.org/nvme into for-linus
Pull NVMe fixes from Christoph
This commit is contained in:
commit
5a60f4b6da
|
@ -1995,6 +1995,9 @@ static ssize_t wwid_show(struct device *dev, struct device_attribute *attr,
|
|||
int serial_len = sizeof(ctrl->serial);
|
||||
int model_len = sizeof(ctrl->model);
|
||||
|
||||
if (!uuid_is_null(&ns->uuid))
|
||||
return sprintf(buf, "uuid.%pU\n", &ns->uuid);
|
||||
|
||||
if (memchr_inv(ns->nguid, 0, sizeof(ns->nguid)))
|
||||
return sprintf(buf, "eui.%16phN\n", ns->nguid);
|
||||
|
||||
|
@ -2709,6 +2712,7 @@ void nvme_kill_queues(struct nvme_ctrl *ctrl)
|
|||
mutex_lock(&ctrl->namespaces_mutex);
|
||||
|
||||
/* Forcibly unquiesce queues to avoid blocking dispatch */
|
||||
if (ctrl->admin_q)
|
||||
blk_mq_unquiesce_queue(ctrl->admin_q);
|
||||
|
||||
list_for_each_entry(ns, &ctrl->namespaces, list) {
|
||||
|
|
|
@ -1888,7 +1888,7 @@ nvme_fc_start_fcp_op(struct nvme_fc_ctrl *ctrl, struct nvme_fc_queue *queue,
|
|||
* the target device is present
|
||||
*/
|
||||
if (ctrl->rport->remoteport.port_state != FC_OBJSTATE_ONLINE)
|
||||
return BLK_STS_IOERR;
|
||||
goto busy;
|
||||
|
||||
if (!nvme_fc_ctrl_get(ctrl))
|
||||
return BLK_STS_IOERR;
|
||||
|
@ -1958,22 +1958,25 @@ nvme_fc_start_fcp_op(struct nvme_fc_ctrl *ctrl, struct nvme_fc_queue *queue,
|
|||
queue->lldd_handle, &op->fcp_req);
|
||||
|
||||
if (ret) {
|
||||
if (op->rq) /* normal request */
|
||||
if (!(op->flags & FCOP_FLAGS_AEN))
|
||||
nvme_fc_unmap_data(ctrl, op->rq, op);
|
||||
/* else - aen. no cleanup needed */
|
||||
|
||||
nvme_fc_ctrl_put(ctrl);
|
||||
|
||||
if (ret != -EBUSY)
|
||||
if (ctrl->rport->remoteport.port_state == FC_OBJSTATE_ONLINE &&
|
||||
ret != -EBUSY)
|
||||
return BLK_STS_IOERR;
|
||||
|
||||
if (op->rq)
|
||||
blk_mq_delay_run_hw_queue(queue->hctx, NVMEFC_QUEUE_DELAY);
|
||||
|
||||
return BLK_STS_RESOURCE;
|
||||
goto busy;
|
||||
}
|
||||
|
||||
return BLK_STS_OK;
|
||||
|
||||
busy:
|
||||
if (!(op->flags & FCOP_FLAGS_AEN) && queue->hctx)
|
||||
blk_mq_delay_run_hw_queue(queue->hctx, NVMEFC_QUEUE_DELAY);
|
||||
|
||||
return BLK_STS_RESOURCE;
|
||||
}
|
||||
|
||||
static blk_status_t
|
||||
|
@ -2802,66 +2805,70 @@ out_fail:
|
|||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
enum {
|
||||
FCT_TRADDR_ERR = 0,
|
||||
FCT_TRADDR_WWNN = 1 << 0,
|
||||
FCT_TRADDR_WWPN = 1 << 1,
|
||||
};
|
||||
|
||||
struct nvmet_fc_traddr {
|
||||
u64 nn;
|
||||
u64 pn;
|
||||
};
|
||||
|
||||
static const match_table_t traddr_opt_tokens = {
|
||||
{ FCT_TRADDR_WWNN, "nn-%s" },
|
||||
{ FCT_TRADDR_WWPN, "pn-%s" },
|
||||
{ FCT_TRADDR_ERR, NULL }
|
||||
};
|
||||
|
||||
static int
|
||||
nvme_fc_parse_address(struct nvmet_fc_traddr *traddr, char *buf)
|
||||
__nvme_fc_parse_u64(substring_t *sstr, u64 *val)
|
||||
{
|
||||
substring_t args[MAX_OPT_ARGS];
|
||||
char *options, *o, *p;
|
||||
int token, ret = 0;
|
||||
u64 token64;
|
||||
|
||||
options = o = kstrdup(buf, GFP_KERNEL);
|
||||
if (!options)
|
||||
return -ENOMEM;
|
||||
if (match_u64(sstr, &token64))
|
||||
return -EINVAL;
|
||||
*val = token64;
|
||||
|
||||
while ((p = strsep(&o, ":\n")) != NULL) {
|
||||
if (!*p)
|
||||
continue;
|
||||
return 0;
|
||||
}
|
||||
|
||||
token = match_token(p, traddr_opt_tokens, args);
|
||||
switch (token) {
|
||||
case FCT_TRADDR_WWNN:
|
||||
if (match_u64(args, &token64)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
traddr->nn = token64;
|
||||
break;
|
||||
case FCT_TRADDR_WWPN:
|
||||
if (match_u64(args, &token64)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
traddr->pn = token64;
|
||||
break;
|
||||
default:
|
||||
pr_warn("unknown traddr token or missing value '%s'\n",
|
||||
p);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* This routine validates and extracts the WWN's from the TRADDR string.
|
||||
* As kernel parsers need the 0x to determine number base, universally
|
||||
* build string to parse with 0x prefix before parsing name strings.
|
||||
*/
|
||||
static int
|
||||
nvme_fc_parse_traddr(struct nvmet_fc_traddr *traddr, char *buf, size_t blen)
|
||||
{
|
||||
char name[2 + NVME_FC_TRADDR_HEXNAMELEN + 1];
|
||||
substring_t wwn = { name, &name[sizeof(name)-1] };
|
||||
int nnoffset, pnoffset;
|
||||
|
||||
out:
|
||||
kfree(options);
|
||||
return ret;
|
||||
/* validate it string one of the 2 allowed formats */
|
||||
if (strnlen(buf, blen) == NVME_FC_TRADDR_MAXLENGTH &&
|
||||
!strncmp(buf, "nn-0x", NVME_FC_TRADDR_OXNNLEN) &&
|
||||
!strncmp(&buf[NVME_FC_TRADDR_MAX_PN_OFFSET],
|
||||
"pn-0x", NVME_FC_TRADDR_OXNNLEN)) {
|
||||
nnoffset = NVME_FC_TRADDR_OXNNLEN;
|
||||
pnoffset = NVME_FC_TRADDR_MAX_PN_OFFSET +
|
||||
NVME_FC_TRADDR_OXNNLEN;
|
||||
} else if ((strnlen(buf, blen) == NVME_FC_TRADDR_MINLENGTH &&
|
||||
!strncmp(buf, "nn-", NVME_FC_TRADDR_NNLEN) &&
|
||||
!strncmp(&buf[NVME_FC_TRADDR_MIN_PN_OFFSET],
|
||||
"pn-", NVME_FC_TRADDR_NNLEN))) {
|
||||
nnoffset = NVME_FC_TRADDR_NNLEN;
|
||||
pnoffset = NVME_FC_TRADDR_MIN_PN_OFFSET + NVME_FC_TRADDR_NNLEN;
|
||||
} else
|
||||
goto out_einval;
|
||||
|
||||
name[0] = '0';
|
||||
name[1] = 'x';
|
||||
name[2 + NVME_FC_TRADDR_HEXNAMELEN] = 0;
|
||||
|
||||
memcpy(&name[2], &buf[nnoffset], NVME_FC_TRADDR_HEXNAMELEN);
|
||||
if (__nvme_fc_parse_u64(&wwn, &traddr->nn))
|
||||
goto out_einval;
|
||||
|
||||
memcpy(&name[2], &buf[pnoffset], NVME_FC_TRADDR_HEXNAMELEN);
|
||||
if (__nvme_fc_parse_u64(&wwn, &traddr->pn))
|
||||
goto out_einval;
|
||||
|
||||
return 0;
|
||||
|
||||
out_einval:
|
||||
pr_warn("%s: bad traddr string\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static struct nvme_ctrl *
|
||||
|
@ -2875,11 +2882,11 @@ nvme_fc_create_ctrl(struct device *dev, struct nvmf_ctrl_options *opts)
|
|||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
ret = nvme_fc_parse_address(&raddr, opts->traddr);
|
||||
ret = nvme_fc_parse_traddr(&raddr, opts->traddr, NVMF_TRADDR_SIZE);
|
||||
if (ret || !raddr.nn || !raddr.pn)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
ret = nvme_fc_parse_address(&laddr, opts->host_traddr);
|
||||
ret = nvme_fc_parse_traddr(&laddr, opts->host_traddr, NVMF_TRADDR_SIZE);
|
||||
if (ret || !laddr.nn || !laddr.pn)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
|
|
|
@ -1619,7 +1619,7 @@ static void nvme_free_host_mem(struct nvme_dev *dev)
|
|||
static int nvme_alloc_host_mem(struct nvme_dev *dev, u64 min, u64 preferred)
|
||||
{
|
||||
struct nvme_host_mem_buf_desc *descs;
|
||||
u32 chunk_size, max_entries;
|
||||
u32 chunk_size, max_entries, len;
|
||||
int i = 0;
|
||||
void **bufs;
|
||||
u64 size = 0, tmp;
|
||||
|
@ -1638,10 +1638,10 @@ retry:
|
|||
if (!bufs)
|
||||
goto out_free_descs;
|
||||
|
||||
for (size = 0; size < preferred; size += chunk_size) {
|
||||
u32 len = min_t(u64, chunk_size, preferred - size);
|
||||
for (size = 0; size < preferred; size += len) {
|
||||
dma_addr_t dma_addr;
|
||||
|
||||
len = min_t(u64, chunk_size, preferred - size);
|
||||
bufs[i] = dma_alloc_attrs(dev->dev, len, &dma_addr, GFP_KERNEL,
|
||||
DMA_ATTR_NO_KERNEL_MAPPING | DMA_ATTR_NO_WARN);
|
||||
if (!bufs[i])
|
||||
|
|
|
@ -2293,66 +2293,70 @@ nvmet_fc_rcv_fcp_abort(struct nvmet_fc_target_port *target_port,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(nvmet_fc_rcv_fcp_abort);
|
||||
|
||||
enum {
|
||||
FCT_TRADDR_ERR = 0,
|
||||
FCT_TRADDR_WWNN = 1 << 0,
|
||||
FCT_TRADDR_WWPN = 1 << 1,
|
||||
};
|
||||
|
||||
struct nvmet_fc_traddr {
|
||||
u64 nn;
|
||||
u64 pn;
|
||||
};
|
||||
|
||||
static const match_table_t traddr_opt_tokens = {
|
||||
{ FCT_TRADDR_WWNN, "nn-%s" },
|
||||
{ FCT_TRADDR_WWPN, "pn-%s" },
|
||||
{ FCT_TRADDR_ERR, NULL }
|
||||
};
|
||||
|
||||
static int
|
||||
nvmet_fc_parse_traddr(struct nvmet_fc_traddr *traddr, char *buf)
|
||||
__nvme_fc_parse_u64(substring_t *sstr, u64 *val)
|
||||
{
|
||||
substring_t args[MAX_OPT_ARGS];
|
||||
char *options, *o, *p;
|
||||
int token, ret = 0;
|
||||
u64 token64;
|
||||
|
||||
options = o = kstrdup(buf, GFP_KERNEL);
|
||||
if (!options)
|
||||
return -ENOMEM;
|
||||
if (match_u64(sstr, &token64))
|
||||
return -EINVAL;
|
||||
*val = token64;
|
||||
|
||||
while ((p = strsep(&o, ":\n")) != NULL) {
|
||||
if (!*p)
|
||||
continue;
|
||||
return 0;
|
||||
}
|
||||
|
||||
token = match_token(p, traddr_opt_tokens, args);
|
||||
switch (token) {
|
||||
case FCT_TRADDR_WWNN:
|
||||
if (match_u64(args, &token64)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
traddr->nn = token64;
|
||||
break;
|
||||
case FCT_TRADDR_WWPN:
|
||||
if (match_u64(args, &token64)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
traddr->pn = token64;
|
||||
break;
|
||||
default:
|
||||
pr_warn("unknown traddr token or missing value '%s'\n",
|
||||
p);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* This routine validates and extracts the WWN's from the TRADDR string.
|
||||
* As kernel parsers need the 0x to determine number base, universally
|
||||
* build string to parse with 0x prefix before parsing name strings.
|
||||
*/
|
||||
static int
|
||||
nvme_fc_parse_traddr(struct nvmet_fc_traddr *traddr, char *buf, size_t blen)
|
||||
{
|
||||
char name[2 + NVME_FC_TRADDR_HEXNAMELEN + 1];
|
||||
substring_t wwn = { name, &name[sizeof(name)-1] };
|
||||
int nnoffset, pnoffset;
|
||||
|
||||
out:
|
||||
kfree(options);
|
||||
return ret;
|
||||
/* validate it string one of the 2 allowed formats */
|
||||
if (strnlen(buf, blen) == NVME_FC_TRADDR_MAXLENGTH &&
|
||||
!strncmp(buf, "nn-0x", NVME_FC_TRADDR_OXNNLEN) &&
|
||||
!strncmp(&buf[NVME_FC_TRADDR_MAX_PN_OFFSET],
|
||||
"pn-0x", NVME_FC_TRADDR_OXNNLEN)) {
|
||||
nnoffset = NVME_FC_TRADDR_OXNNLEN;
|
||||
pnoffset = NVME_FC_TRADDR_MAX_PN_OFFSET +
|
||||
NVME_FC_TRADDR_OXNNLEN;
|
||||
} else if ((strnlen(buf, blen) == NVME_FC_TRADDR_MINLENGTH &&
|
||||
!strncmp(buf, "nn-", NVME_FC_TRADDR_NNLEN) &&
|
||||
!strncmp(&buf[NVME_FC_TRADDR_MIN_PN_OFFSET],
|
||||
"pn-", NVME_FC_TRADDR_NNLEN))) {
|
||||
nnoffset = NVME_FC_TRADDR_NNLEN;
|
||||
pnoffset = NVME_FC_TRADDR_MIN_PN_OFFSET + NVME_FC_TRADDR_NNLEN;
|
||||
} else
|
||||
goto out_einval;
|
||||
|
||||
name[0] = '0';
|
||||
name[1] = 'x';
|
||||
name[2 + NVME_FC_TRADDR_HEXNAMELEN] = 0;
|
||||
|
||||
memcpy(&name[2], &buf[nnoffset], NVME_FC_TRADDR_HEXNAMELEN);
|
||||
if (__nvme_fc_parse_u64(&wwn, &traddr->nn))
|
||||
goto out_einval;
|
||||
|
||||
memcpy(&name[2], &buf[pnoffset], NVME_FC_TRADDR_HEXNAMELEN);
|
||||
if (__nvme_fc_parse_u64(&wwn, &traddr->pn))
|
||||
goto out_einval;
|
||||
|
||||
return 0;
|
||||
|
||||
out_einval:
|
||||
pr_warn("%s: bad traddr string\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -2370,7 +2374,8 @@ nvmet_fc_add_port(struct nvmet_port *port)
|
|||
|
||||
/* map the traddr address info to a target port */
|
||||
|
||||
ret = nvmet_fc_parse_traddr(&traddr, port->disc_addr.traddr);
|
||||
ret = nvme_fc_parse_traddr(&traddr, port->disc_addr.traddr,
|
||||
sizeof(port->disc_addr.traddr));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -334,5 +334,24 @@ struct fcnvme_ls_disconnect_acc {
|
|||
#define NVME_FC_LS_TIMEOUT_SEC 2 /* 2 seconds */
|
||||
#define NVME_FC_TGTOP_TIMEOUT_SEC 2 /* 2 seconds */
|
||||
|
||||
/*
|
||||
* TRADDR string must be of form "nn-<16hexdigits>:pn-<16hexdigits>"
|
||||
* the string is allowed to be specified with or without a "0x" prefix
|
||||
* infront of the <16hexdigits>. Without is considered the "min" string
|
||||
* and with is considered the "max" string. The hexdigits may be upper
|
||||
* or lower case.
|
||||
*/
|
||||
#define NVME_FC_TRADDR_NNLEN 3 /* "?n-" */
|
||||
#define NVME_FC_TRADDR_OXNNLEN 5 /* "?n-0x" */
|
||||
#define NVME_FC_TRADDR_HEXNAMELEN 16
|
||||
#define NVME_FC_TRADDR_MINLENGTH \
|
||||
(2 * (NVME_FC_TRADDR_NNLEN + NVME_FC_TRADDR_HEXNAMELEN) + 1)
|
||||
#define NVME_FC_TRADDR_MAXLENGTH \
|
||||
(2 * (NVME_FC_TRADDR_OXNNLEN + NVME_FC_TRADDR_HEXNAMELEN) + 1)
|
||||
#define NVME_FC_TRADDR_MIN_PN_OFFSET \
|
||||
(NVME_FC_TRADDR_NNLEN + NVME_FC_TRADDR_HEXNAMELEN + 1)
|
||||
#define NVME_FC_TRADDR_MAX_PN_OFFSET \
|
||||
(NVME_FC_TRADDR_OXNNLEN + NVME_FC_TRADDR_HEXNAMELEN + 1)
|
||||
|
||||
|
||||
#endif /* _NVME_FC_H */
|
||||
|
|
|
@ -1006,7 +1006,7 @@ static inline bool nvme_is_write(struct nvme_command *cmd)
|
|||
* Why can't we simply have a Fabrics In and Fabrics out command?
|
||||
*/
|
||||
if (unlikely(cmd->common.opcode == nvme_fabrics_command))
|
||||
return cmd->fabrics.opcode & 1;
|
||||
return cmd->fabrics.fctype & 1;
|
||||
return cmd->common.opcode & 1;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue