]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/nvme/host/fc.c
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dledford/rdma
[linux.git] / drivers / nvme / host / fc.c
index d666ada39a9be6d6f27fff36904af75063c035d6..5c2a08ef08bafd8351b0000ac5029620a9f19522 100644 (file)
@@ -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 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
        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;
+
+       /* 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;
 
-out:
-       kfree(options);
-       return ret;
+       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);