Commit 5a60f4b6 authored by Jens Axboe's avatar Jens Axboe

Merge branch 'nvme-4.13' of git://git.infradead.org/nvme into for-linus

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