|
@@ -120,14 +120,13 @@ static void zfcp_wka_port_put(struct zfcp_wka_port *wka_port)
|
|
|
schedule_delayed_work(&wka_port->work, HZ / 100);
|
|
|
}
|
|
|
|
|
|
-void zfcp_fc_nameserver_init(struct zfcp_adapter *adapter)
|
|
|
+static void zfcp_fc_wka_port_init(struct zfcp_wka_port *wka_port, u32 d_id,
|
|
|
+ struct zfcp_adapter *adapter)
|
|
|
{
|
|
|
- struct zfcp_wka_port *wka_port = &adapter->nsp;
|
|
|
-
|
|
|
init_waitqueue_head(&wka_port->completion_wq);
|
|
|
|
|
|
wka_port->adapter = adapter;
|
|
|
- wka_port->d_id = ZFCP_DID_DIRECTORY_SERVICE;
|
|
|
+ wka_port->d_id = d_id;
|
|
|
|
|
|
wka_port->status = ZFCP_WKA_PORT_OFFLINE;
|
|
|
atomic_set(&wka_port->refcount, 0);
|
|
@@ -143,6 +142,17 @@ void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *wka)
|
|
|
mutex_unlock(&wka->mutex);
|
|
|
}
|
|
|
|
|
|
+void zfcp_fc_wka_ports_init(struct zfcp_adapter *adapter)
|
|
|
+{
|
|
|
+ struct zfcp_wka_ports *gs = adapter->gs;
|
|
|
+
|
|
|
+ zfcp_fc_wka_port_init(&gs->ms, FC_FID_MGMT_SERV, adapter);
|
|
|
+ zfcp_fc_wka_port_init(&gs->ts, FC_FID_TIME_SERV, adapter);
|
|
|
+ zfcp_fc_wka_port_init(&gs->ds, FC_FID_DIR_SERV, adapter);
|
|
|
+ zfcp_fc_wka_port_init(&gs->as, FC_FID_ALIASES, adapter);
|
|
|
+ zfcp_fc_wka_port_init(&gs->ks, FC_FID_SEC_KEY, adapter);
|
|
|
+}
|
|
|
+
|
|
|
static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range,
|
|
|
struct fcp_rscn_element *elem)
|
|
|
{
|
|
@@ -282,7 +292,7 @@ int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action,
|
|
|
|
|
|
/* setup parameters for send generic command */
|
|
|
gid_pn->port = erp_action->port;
|
|
|
- gid_pn->ct.wka_port = &adapter->nsp;
|
|
|
+ gid_pn->ct.wka_port = &adapter->gs->ds;
|
|
|
gid_pn->ct.handler = zfcp_fc_ns_handler;
|
|
|
gid_pn->ct.handler_data = (unsigned long) &compl_rec;
|
|
|
gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT;
|
|
@@ -329,13 +339,13 @@ int zfcp_fc_ns_gid_pn(struct zfcp_erp_action *erp_action)
|
|
|
|
|
|
memset(gid_pn, 0, sizeof(*gid_pn));
|
|
|
|
|
|
- ret = zfcp_wka_port_get(&adapter->nsp);
|
|
|
+ ret = zfcp_wka_port_get(&adapter->gs->ds);
|
|
|
if (ret)
|
|
|
goto out;
|
|
|
|
|
|
ret = zfcp_fc_ns_gid_pn_request(erp_action, gid_pn);
|
|
|
|
|
|
- zfcp_wka_port_put(&adapter->nsp);
|
|
|
+ zfcp_wka_port_put(&adapter->gs->ds);
|
|
|
out:
|
|
|
mempool_free(gid_pn, adapter->pool.data_gid_pn);
|
|
|
return ret;
|
|
@@ -525,7 +535,7 @@ static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft,
|
|
|
req->fc4_type = ZFCP_CT_SCSI_FCP;
|
|
|
|
|
|
/* prepare zfcp_send_ct */
|
|
|
- ct->wka_port = &adapter->nsp;
|
|
|
+ ct->wka_port = &adapter->gs->ds;
|
|
|
ct->handler = zfcp_fc_ns_handler;
|
|
|
ct->handler_data = (unsigned long)&compl_rec;
|
|
|
ct->timeout = 10;
|
|
@@ -644,7 +654,7 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter)
|
|
|
fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPIV)
|
|
|
return 0;
|
|
|
|
|
|
- ret = zfcp_wka_port_get(&adapter->nsp);
|
|
|
+ ret = zfcp_wka_port_get(&adapter->gs->ds);
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
|
|
@@ -666,7 +676,7 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter)
|
|
|
}
|
|
|
zfcp_free_sg_env(gpn_ft, buf_num);
|
|
|
out:
|
|
|
- zfcp_wka_port_put(&adapter->nsp);
|
|
|
+ zfcp_wka_port_put(&adapter->gs->ds);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -675,3 +685,161 @@ void _zfcp_scan_ports_later(struct work_struct *work)
|
|
|
{
|
|
|
zfcp_scan_ports(container_of(work, struct zfcp_adapter, scan_work));
|
|
|
}
|
|
|
+
|
|
|
+struct zfcp_els_fc_job {
|
|
|
+ struct zfcp_send_els els;
|
|
|
+ struct fc_bsg_job *job;
|
|
|
+};
|
|
|
+
|
|
|
+static void zfcp_fc_generic_els_handler(unsigned long data)
|
|
|
+{
|
|
|
+ struct zfcp_els_fc_job *els_fc_job = (struct zfcp_els_fc_job *) data;
|
|
|
+ struct fc_bsg_job *job = els_fc_job->job;
|
|
|
+ struct fc_bsg_reply *reply = job->reply;
|
|
|
+
|
|
|
+ if (els_fc_job->els.status) {
|
|
|
+ /* request rejected or timed out */
|
|
|
+ reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_REJECT;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK;
|
|
|
+ reply->reply_payload_rcv_len = blk_rq_bytes(job->req->next_rq);
|
|
|
+
|
|
|
+out:
|
|
|
+ job->state_flags = FC_RQST_STATE_DONE;
|
|
|
+ job->job_done(job);
|
|
|
+ kfree(els_fc_job);
|
|
|
+}
|
|
|
+
|
|
|
+int zfcp_fc_execute_els_fc_job(struct fc_bsg_job *job)
|
|
|
+{
|
|
|
+ struct zfcp_els_fc_job *els_fc_job;
|
|
|
+ struct fc_rport *rport = job->rport;
|
|
|
+ struct Scsi_Host *shost;
|
|
|
+ struct zfcp_adapter *adapter;
|
|
|
+ struct zfcp_port *port;
|
|
|
+ u8 *port_did;
|
|
|
+
|
|
|
+ shost = rport ? rport_to_shost(rport) : job->shost;
|
|
|
+ adapter = (struct zfcp_adapter *)shost->hostdata[0];
|
|
|
+
|
|
|
+ if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ els_fc_job = kzalloc(sizeof(struct zfcp_els_fc_job), GFP_KERNEL);
|
|
|
+ if (!els_fc_job)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ els_fc_job->els.adapter = adapter;
|
|
|
+ if (rport) {
|
|
|
+ read_lock_irq(&zfcp_data.config_lock);
|
|
|
+ port = rport->dd_data;
|
|
|
+ if (port)
|
|
|
+ zfcp_port_get(port);
|
|
|
+ read_unlock_irq(&zfcp_data.config_lock);
|
|
|
+ if (!port) {
|
|
|
+ kfree(els_fc_job);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ els_fc_job->els.port = port;
|
|
|
+ els_fc_job->els.d_id = port->d_id;
|
|
|
+ zfcp_port_put(port);
|
|
|
+ } else {
|
|
|
+ port_did = job->request->rqst_data.h_els.port_id;
|
|
|
+ els_fc_job->els.d_id = (port_did[0] << 16) +
|
|
|
+ (port_did[1] << 8) + port_did[2];
|
|
|
+ }
|
|
|
+
|
|
|
+ els_fc_job->els.req = job->request_payload.sg_list;
|
|
|
+ els_fc_job->els.resp = job->reply_payload.sg_list;
|
|
|
+ els_fc_job->els.handler = zfcp_fc_generic_els_handler;
|
|
|
+ els_fc_job->els.handler_data = (unsigned long) els_fc_job;
|
|
|
+ els_fc_job->job = job;
|
|
|
+
|
|
|
+ return zfcp_fsf_send_els(&els_fc_job->els);
|
|
|
+}
|
|
|
+
|
|
|
+struct zfcp_ct_fc_job {
|
|
|
+ struct zfcp_send_ct ct;
|
|
|
+ struct fc_bsg_job *job;
|
|
|
+};
|
|
|
+
|
|
|
+static void zfcp_fc_generic_ct_handler(unsigned long data)
|
|
|
+{
|
|
|
+ struct zfcp_ct_fc_job *ct_fc_job = (struct zfcp_ct_fc_job *) data;
|
|
|
+ struct fc_bsg_job *job = ct_fc_job->job;
|
|
|
+
|
|
|
+ job->reply->reply_data.ctels_reply.status = ct_fc_job->ct.status ?
|
|
|
+ FC_CTELS_STATUS_REJECT : FC_CTELS_STATUS_OK;
|
|
|
+ job->state_flags = FC_RQST_STATE_DONE;
|
|
|
+ job->reply->reply_payload_rcv_len = blk_rq_bytes(job->req->next_rq);
|
|
|
+ job->job_done(job);
|
|
|
+
|
|
|
+ zfcp_wka_port_put(ct_fc_job->ct.wka_port);
|
|
|
+
|
|
|
+ kfree(ct_fc_job);
|
|
|
+}
|
|
|
+
|
|
|
+int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *job)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+ u8 gs_type;
|
|
|
+ struct fc_rport *rport = job->rport;
|
|
|
+ struct Scsi_Host *shost;
|
|
|
+ struct zfcp_adapter *adapter;
|
|
|
+ struct zfcp_ct_fc_job *ct_fc_job;
|
|
|
+ u32 preamble_word1;
|
|
|
+
|
|
|
+ shost = rport ? rport_to_shost(rport) : job->shost;
|
|
|
+
|
|
|
+ adapter = (struct zfcp_adapter *)shost->hostdata[0];
|
|
|
+ if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ ct_fc_job = kzalloc(sizeof(struct zfcp_ct_fc_job), GFP_KERNEL);
|
|
|
+ if (!ct_fc_job)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ preamble_word1 = job->request->rqst_data.r_ct.preamble_word1;
|
|
|
+ gs_type = (preamble_word1 & 0xff000000) >> 24;
|
|
|
+
|
|
|
+ switch (gs_type) {
|
|
|
+ case FC_FST_ALIAS:
|
|
|
+ ct_fc_job->ct.wka_port = &adapter->gs->as;
|
|
|
+ break;
|
|
|
+ case FC_FST_MGMT:
|
|
|
+ ct_fc_job->ct.wka_port = &adapter->gs->ms;
|
|
|
+ break;
|
|
|
+ case FC_FST_TIME:
|
|
|
+ ct_fc_job->ct.wka_port = &adapter->gs->ts;
|
|
|
+ break;
|
|
|
+ case FC_FST_DIR:
|
|
|
+ ct_fc_job->ct.wka_port = &adapter->gs->ds;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ kfree(ct_fc_job);
|
|
|
+ return -EINVAL; /* no such service */
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = zfcp_wka_port_get(ct_fc_job->ct.wka_port);
|
|
|
+ if (ret) {
|
|
|
+ kfree(ct_fc_job);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ ct_fc_job->ct.req = job->request_payload.sg_list;
|
|
|
+ ct_fc_job->ct.resp = job->reply_payload.sg_list;
|
|
|
+ ct_fc_job->ct.timeout = ZFCP_FSF_REQUEST_TIMEOUT;
|
|
|
+ ct_fc_job->ct.handler = zfcp_fc_generic_ct_handler;
|
|
|
+ ct_fc_job->ct.handler_data = (unsigned long) ct_fc_job;
|
|
|
+ ct_fc_job->ct.completion = NULL;
|
|
|
+ ct_fc_job->job = job;
|
|
|
+
|
|
|
+ ret = zfcp_fsf_send_ct(&ct_fc_job->ct, NULL, NULL);
|
|
|
+ if (ret) {
|
|
|
+ kfree(ct_fc_job);
|
|
|
+ zfcp_wka_port_put(ct_fc_job->ct.wka_port);
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+}
|