|
@@ -11,6 +11,7 @@
|
|
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/types.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/slab.h>
|
|
|
|
+#include <linux/utsname.h>
|
|
#include <scsi/fc/fc_els.h>
|
|
#include <scsi/fc/fc_els.h>
|
|
#include <scsi/libfc.h>
|
|
#include <scsi/libfc.h>
|
|
#include "zfcp_ext.h"
|
|
#include "zfcp_ext.h"
|
|
@@ -696,6 +697,125 @@ out:
|
|
zfcp_fc_wka_port_put(&adapter->gs->ds);
|
|
zfcp_fc_wka_port_put(&adapter->gs->ds);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int zfcp_fc_gspn(struct zfcp_adapter *adapter,
|
|
|
|
+ struct zfcp_fc_req *fc_req)
|
|
|
|
+{
|
|
|
|
+ DECLARE_COMPLETION_ONSTACK(completion);
|
|
|
|
+ char devno[] = "DEVNO:";
|
|
|
|
+ struct zfcp_fsf_ct_els *ct_els = &fc_req->ct_els;
|
|
|
|
+ struct zfcp_fc_gspn_req *gspn_req = &fc_req->u.gspn.req;
|
|
|
|
+ struct zfcp_fc_gspn_rsp *gspn_rsp = &fc_req->u.gspn.rsp;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ zfcp_fc_ct_ns_init(&gspn_req->ct_hdr, FC_NS_GSPN_ID,
|
|
|
|
+ FC_SYMBOLIC_NAME_SIZE);
|
|
|
|
+ hton24(gspn_req->gspn.fp_fid, fc_host_port_id(adapter->scsi_host));
|
|
|
|
+
|
|
|
|
+ sg_init_one(&fc_req->sg_req, gspn_req, sizeof(*gspn_req));
|
|
|
|
+ sg_init_one(&fc_req->sg_rsp, gspn_rsp, sizeof(*gspn_rsp));
|
|
|
|
+
|
|
|
|
+ ct_els->handler = zfcp_fc_complete;
|
|
|
|
+ ct_els->handler_data = &completion;
|
|
|
|
+ ct_els->req = &fc_req->sg_req;
|
|
|
|
+ ct_els->resp = &fc_req->sg_rsp;
|
|
|
|
+
|
|
|
|
+ ret = zfcp_fsf_send_ct(&adapter->gs->ds, ct_els, NULL,
|
|
|
|
+ ZFCP_FC_CTELS_TMO);
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ wait_for_completion(&completion);
|
|
|
|
+ if (ct_els->status)
|
|
|
|
+ return ct_els->status;
|
|
|
|
+
|
|
|
|
+ if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_NPIV &&
|
|
|
|
+ !(strstr(gspn_rsp->gspn.fp_name, devno)))
|
|
|
|
+ snprintf(fc_host_symbolic_name(adapter->scsi_host),
|
|
|
|
+ FC_SYMBOLIC_NAME_SIZE, "%s%s %s NAME: %s",
|
|
|
|
+ gspn_rsp->gspn.fp_name, devno,
|
|
|
|
+ dev_name(&adapter->ccw_device->dev),
|
|
|
|
+ init_utsname()->nodename);
|
|
|
|
+ else
|
|
|
|
+ strlcpy(fc_host_symbolic_name(adapter->scsi_host),
|
|
|
|
+ gspn_rsp->gspn.fp_name, FC_SYMBOLIC_NAME_SIZE);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void zfcp_fc_rspn(struct zfcp_adapter *adapter,
|
|
|
|
+ struct zfcp_fc_req *fc_req)
|
|
|
|
+{
|
|
|
|
+ DECLARE_COMPLETION_ONSTACK(completion);
|
|
|
|
+ struct Scsi_Host *shost = adapter->scsi_host;
|
|
|
|
+ struct zfcp_fsf_ct_els *ct_els = &fc_req->ct_els;
|
|
|
|
+ struct zfcp_fc_rspn_req *rspn_req = &fc_req->u.rspn.req;
|
|
|
|
+ struct fc_ct_hdr *rspn_rsp = &fc_req->u.rspn.rsp;
|
|
|
|
+ int ret, len;
|
|
|
|
+
|
|
|
|
+ zfcp_fc_ct_ns_init(&rspn_req->ct_hdr, FC_NS_RSPN_ID,
|
|
|
|
+ FC_SYMBOLIC_NAME_SIZE);
|
|
|
|
+ hton24(rspn_req->rspn.fr_fid.fp_fid, fc_host_port_id(shost));
|
|
|
|
+ len = strlcpy(rspn_req->rspn.fr_name, fc_host_symbolic_name(shost),
|
|
|
|
+ FC_SYMBOLIC_NAME_SIZE);
|
|
|
|
+ rspn_req->rspn.fr_name_len = len;
|
|
|
|
+
|
|
|
|
+ sg_init_one(&fc_req->sg_req, rspn_req, sizeof(*rspn_req));
|
|
|
|
+ sg_init_one(&fc_req->sg_rsp, rspn_rsp, sizeof(*rspn_rsp));
|
|
|
|
+
|
|
|
|
+ ct_els->handler = zfcp_fc_complete;
|
|
|
|
+ ct_els->handler_data = &completion;
|
|
|
|
+ ct_els->req = &fc_req->sg_req;
|
|
|
|
+ ct_els->resp = &fc_req->sg_rsp;
|
|
|
|
+
|
|
|
|
+ ret = zfcp_fsf_send_ct(&adapter->gs->ds, ct_els, NULL,
|
|
|
|
+ ZFCP_FC_CTELS_TMO);
|
|
|
|
+ if (!ret)
|
|
|
|
+ wait_for_completion(&completion);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * zfcp_fc_sym_name_update - Retrieve and update the symbolic port name
|
|
|
|
+ * @work: ns_up_work of the adapter where to update the symbolic port name
|
|
|
|
+ *
|
|
|
|
+ * Retrieve the current symbolic port name that may have been set by
|
|
|
|
+ * the hardware using the GSPN request and update the fc_host
|
|
|
|
+ * symbolic_name sysfs attribute. When running in NPIV mode (and hence
|
|
|
|
+ * the port name is unique for this system), update the symbolic port
|
|
|
|
+ * name to add Linux specific information and update the FC nameserver
|
|
|
|
+ * using the RSPN request.
|
|
|
|
+ */
|
|
|
|
+void zfcp_fc_sym_name_update(struct work_struct *work)
|
|
|
|
+{
|
|
|
|
+ struct zfcp_adapter *adapter = container_of(work, struct zfcp_adapter,
|
|
|
|
+ ns_up_work);
|
|
|
|
+ int ret;
|
|
|
|
+ struct zfcp_fc_req *fc_req;
|
|
|
|
+
|
|
|
|
+ if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT &&
|
|
|
|
+ fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPIV)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ fc_req = kmem_cache_zalloc(zfcp_fc_req_cache, GFP_KERNEL);
|
|
|
|
+ if (!fc_req)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ ret = zfcp_fc_wka_port_get(&adapter->gs->ds);
|
|
|
|
+ if (ret)
|
|
|
|
+ goto out_free;
|
|
|
|
+
|
|
|
|
+ ret = zfcp_fc_gspn(adapter, fc_req);
|
|
|
|
+ if (ret || fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPIV)
|
|
|
|
+ goto out_ds_put;
|
|
|
|
+
|
|
|
|
+ memset(fc_req, 0, sizeof(*fc_req));
|
|
|
|
+ zfcp_fc_rspn(adapter, fc_req);
|
|
|
|
+
|
|
|
|
+out_ds_put:
|
|
|
|
+ zfcp_fc_wka_port_put(&adapter->gs->ds);
|
|
|
|
+out_free:
|
|
|
|
+ kmem_cache_free(zfcp_fc_req_cache, fc_req);
|
|
|
|
+}
|
|
|
|
+
|
|
static void zfcp_fc_ct_els_job_handler(void *data)
|
|
static void zfcp_fc_ct_els_job_handler(void *data)
|
|
{
|
|
{
|
|
struct fc_bsg_job *job = data;
|
|
struct fc_bsg_job *job = data;
|