]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/s390/scsi/zfcp_fc.c
Merge branch 'ec' into release
[mv-sheeva.git] / drivers / s390 / scsi / zfcp_fc.c
index 47daebfa7e59af2f7b17e91184182199ed7bb26f..722f22de875351d564595ff019322a3550982687 100644 (file)
@@ -25,14 +25,6 @@ static u32 rscn_range_mask[] = {
        [RSCN_FABRIC_ADDRESS]           = 0x000000,
 };
 
-struct ct_iu_gpn_ft_req {
-       struct ct_hdr header;
-       u8 flags;
-       u8 domain_id_scope;
-       u8 area_id_scope;
-       u8 fc4_type;
-} __attribute__ ((packed));
-
 struct gpn_ft_resp_acc {
        u8 control;
        u8 port_id[3];
@@ -65,7 +57,7 @@ struct zfcp_fc_ns_handler_data {
        unsigned long handler_data;
 };
 
-static int zfcp_wka_port_get(struct zfcp_wka_port *wka_port)
+static int zfcp_fc_wka_port_get(struct zfcp_wka_port *wka_port)
 {
        if (mutex_lock_interruptible(&wka_port->mutex))
                return -ERESTARTSYS;
@@ -90,7 +82,7 @@ static int zfcp_wka_port_get(struct zfcp_wka_port *wka_port)
        return -EIO;
 }
 
-static void zfcp_wka_port_offline(struct work_struct *work)
+static void zfcp_fc_wka_port_offline(struct work_struct *work)
 {
        struct delayed_work *dw = to_delayed_work(work);
        struct zfcp_wka_port *wka_port =
@@ -110,7 +102,7 @@ out:
        mutex_unlock(&wka_port->mutex);
 }
 
-static void zfcp_wka_port_put(struct zfcp_wka_port *wka_port)
+static void zfcp_fc_wka_port_put(struct zfcp_wka_port *wka_port)
 {
        if (atomic_dec_return(&wka_port->refcount) != 0)
                return;
@@ -129,10 +121,10 @@ static void zfcp_fc_wka_port_init(struct zfcp_wka_port *wka_port, u32 d_id,
        wka_port->status = ZFCP_WKA_PORT_OFFLINE;
        atomic_set(&wka_port->refcount, 0);
        mutex_init(&wka_port->mutex);
-       INIT_DELAYED_WORK(&wka_port->work, zfcp_wka_port_offline);
+       INIT_DELAYED_WORK(&wka_port->work, zfcp_fc_wka_port_offline);
 }
 
-void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *wka)
+static void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *wka)
 {
        cancel_delayed_work_sync(&wka->work);
        mutex_lock(&wka->mutex);
@@ -140,15 +132,13 @@ 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)
+void zfcp_fc_wka_ports_force_offline(struct zfcp_wka_ports *gs)
 {
-       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);
+       zfcp_fc_wka_port_force_offline(&gs->ms);
+       zfcp_fc_wka_port_force_offline(&gs->ts);
+       zfcp_fc_wka_port_force_offline(&gs->ds);
+       zfcp_fc_wka_port_force_offline(&gs->as);
+       zfcp_fc_wka_port_force_offline(&gs->ks);
 }
 
 static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range,
@@ -160,7 +150,7 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range,
        read_lock_irqsave(&zfcp_data.config_lock, flags);
        list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) {
                if ((port->d_id & range) == (elem->nport_did & range))
-                       zfcp_test_link(port);
+                       zfcp_fc_test_link(port);
                if (!port->d_id)
                        zfcp_erp_port_reopen(port,
                                             ZFCP_STATUS_COMMON_ERP_FAILED,
@@ -241,7 +231,7 @@ void zfcp_fc_incoming_els(struct zfcp_fsf_req *fsf_req)
                (struct fsf_status_read_buffer *) fsf_req->data;
        unsigned int els_type = status_buffer->payload.data[0];
 
-       zfcp_san_dbf_event_incoming_els(fsf_req);
+       zfcp_dbf_san_incoming_els(fsf_req);
        if (els_type == LS_PLOGI)
                zfcp_fc_incoming_plogi(fsf_req);
        else if (els_type == LS_LOGO)
@@ -281,19 +271,18 @@ static void zfcp_fc_ns_gid_pn_eval(unsigned long data)
        port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK;
 }
 
-int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action,
+static int zfcp_fc_ns_gid_pn_request(struct zfcp_port *port,
                                     struct zfcp_gid_pn_data *gid_pn)
 {
-       struct zfcp_adapter *adapter = erp_action->adapter;
+       struct zfcp_adapter *adapter = port->adapter;
        struct zfcp_fc_ns_handler_data compl_rec;
        int ret;
 
        /* setup parameters for send generic command */
-       gid_pn->port = erp_action->port;
+       gid_pn->port = port;
        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;
        gid_pn->ct.req = &gid_pn->req;
        gid_pn->ct.resp = &gid_pn->resp;
        sg_init_one(&gid_pn->req, &gid_pn->ct_iu_req,
@@ -308,13 +297,12 @@ int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action,
        gid_pn->ct_iu_req.header.options = ZFCP_CT_SYNCHRONOUS;
        gid_pn->ct_iu_req.header.cmd_rsp_code = ZFCP_CT_GID_PN;
        gid_pn->ct_iu_req.header.max_res_size = ZFCP_CT_SIZE_ONE_PAGE / 4;
-       gid_pn->ct_iu_req.wwpn = erp_action->port->wwpn;
+       gid_pn->ct_iu_req.wwpn = port->wwpn;
 
        init_completion(&compl_rec.done);
        compl_rec.handler = zfcp_fc_ns_gid_pn_eval;
        compl_rec.handler_data = (unsigned long) gid_pn;
-       ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.fsf_req_erp,
-                              erp_action);
+       ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.gid_pn_req);
        if (!ret)
                wait_for_completion(&compl_rec.done);
        return ret;
@@ -322,33 +310,56 @@ int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action,
 
 /**
  * zfcp_fc_ns_gid_pn_request - initiate GID_PN nameserver request
- * @erp_action: pointer to zfcp_erp_action where GID_PN request is needed
+ * @port: port where GID_PN request is needed
  * return: -ENOMEM on error, 0 otherwise
  */
-int zfcp_fc_ns_gid_pn(struct zfcp_erp_action *erp_action)
+static int zfcp_fc_ns_gid_pn(struct zfcp_port *port)
 {
        int ret;
        struct zfcp_gid_pn_data *gid_pn;
-       struct zfcp_adapter *adapter = erp_action->adapter;
+       struct zfcp_adapter *adapter = port->adapter;
 
-       gid_pn = mempool_alloc(adapter->pool.data_gid_pn, GFP_ATOMIC);
+       gid_pn = mempool_alloc(adapter->pool.gid_pn_data, GFP_ATOMIC);
        if (!gid_pn)
                return -ENOMEM;
 
        memset(gid_pn, 0, sizeof(*gid_pn));
 
-       ret = zfcp_wka_port_get(&adapter->gs->ds);
+       ret = zfcp_fc_wka_port_get(&adapter->gs->ds);
        if (ret)
                goto out;
 
-       ret = zfcp_fc_ns_gid_pn_request(erp_action, gid_pn);
+       ret = zfcp_fc_ns_gid_pn_request(port, gid_pn);
 
-       zfcp_wka_port_put(&adapter->gs->ds);
+       zfcp_fc_wka_port_put(&adapter->gs->ds);
 out:
-       mempool_free(gid_pn, adapter->pool.data_gid_pn);
+       mempool_free(gid_pn, adapter->pool.gid_pn_data);
        return ret;
 }
 
+void zfcp_fc_port_did_lookup(struct work_struct *work)
+{
+       int ret;
+       struct zfcp_port *port = container_of(work, struct zfcp_port,
+                                             gid_pn_work);
+
+       ret = zfcp_fc_ns_gid_pn(port);
+       if (ret) {
+               /* could not issue gid_pn for some reason */
+               zfcp_erp_adapter_reopen(port->adapter, 0, "fcgpn_1", NULL);
+               goto out;
+       }
+
+       if (!port->d_id) {
+               zfcp_erp_port_failed(port, "fcgpn_2", NULL);
+               goto out;
+       }
+
+       zfcp_erp_port_reopen(port, 0, "fcgpn_3", NULL);
+out:
+       zfcp_port_put(port);
+}
+
 /**
  * zfcp_fc_plogi_evaluate - evaluate PLOGI playload
  * @port: zfcp_port structure
@@ -404,6 +415,7 @@ static void zfcp_fc_adisc_handler(unsigned long data)
        /* port is good, unblock rport without going through erp */
        zfcp_scsi_schedule_rport_register(port);
  out:
+       atomic_clear_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status);
        zfcp_port_put(port);
        kfree(adisc);
 }
@@ -450,28 +462,36 @@ void zfcp_fc_link_test_work(struct work_struct *work)
        port->rport_task = RPORT_DEL;
        zfcp_scsi_rport_work(&port->rport_work);
 
+       /* only issue one test command at one time per port */
+       if (atomic_read(&port->status) & ZFCP_STATUS_PORT_LINK_TEST)
+               goto out;
+
+       atomic_set_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status);
+
        retval = zfcp_fc_adisc(port);
        if (retval == 0)
                return;
 
        /* send of ADISC was not possible */
+       atomic_clear_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status);
        zfcp_erp_port_forced_reopen(port, 0, "fcltwk1", NULL);
 
+out:
        zfcp_port_put(port);
 }
 
 /**
- * zfcp_test_link - lightweight link test procedure
+ * zfcp_fc_test_link - lightweight link test procedure
  * @port: port to be tested
  *
  * Test status of a link to a remote port using the ELS command ADISC.
  * If there is a problem with the remote port, error recovery steps
  * will be triggered.
  */
-void zfcp_test_link(struct zfcp_port *port)
+void zfcp_fc_test_link(struct zfcp_port *port)
 {
        zfcp_port_get(port);
-       if (!queue_work(zfcp_data.work_queue, &port->test_link_work))
+       if (!queue_work(port->adapter->work_queue, &port->test_link_work))
                zfcp_port_put(port);
 }
 
@@ -479,7 +499,7 @@ static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft, int buf_num)
 {
        struct scatterlist *sg = &gpn_ft->sg_req;
 
-       kfree(sg_virt(sg)); /* free request buffer */
+       kmem_cache_free(zfcp_data.gpn_ft_cache, sg_virt(sg));
        zfcp_sg_free_table(gpn_ft->sg_resp, buf_num);
 
        kfree(gpn_ft);
@@ -494,7 +514,7 @@ static struct zfcp_gpn_ft *zfcp_alloc_sg_env(int buf_num)
        if (!gpn_ft)
                return NULL;
 
-       req = kzalloc(sizeof(struct ct_iu_gpn_ft_req), GFP_KERNEL);
+       req = kmem_cache_alloc(zfcp_data.gpn_ft_cache, GFP_KERNEL);
        if (!req) {
                kfree(gpn_ft);
                gpn_ft = NULL;
@@ -511,9 +531,8 @@ out:
 }
 
 
-static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft,
-                                 struct zfcp_adapter *adapter,
-                                 int max_bytes)
+static int zfcp_fc_send_gpn_ft(struct zfcp_gpn_ft *gpn_ft,
+                              struct zfcp_adapter *adapter, int max_bytes)
 {
        struct zfcp_send_ct *ct = &gpn_ft->ct;
        struct ct_iu_gpn_ft_req *req = sg_virt(&gpn_ft->sg_req);
@@ -536,19 +555,18 @@ static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft,
        ct->wka_port = &adapter->gs->ds;
        ct->handler = zfcp_fc_ns_handler;
        ct->handler_data = (unsigned long)&compl_rec;
-       ct->timeout = 10;
        ct->req = &gpn_ft->sg_req;
        ct->resp = gpn_ft->sg_resp;
 
        init_completion(&compl_rec.done);
        compl_rec.handler = NULL;
-       ret = zfcp_fsf_send_ct(ct, NULL, NULL);
+       ret = zfcp_fsf_send_ct(ct, NULL);
        if (!ret)
                wait_for_completion(&compl_rec.done);
        return ret;
 }
 
-static void zfcp_validate_port(struct zfcp_port *port)
+static void zfcp_fc_validate_port(struct zfcp_port *port)
 {
        struct zfcp_adapter *adapter = port->adapter;
 
@@ -568,7 +586,7 @@ static void zfcp_validate_port(struct zfcp_port *port)
        zfcp_port_dequeue(port);
 }
 
-static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries)
+static int zfcp_fc_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries)
 {
        struct zfcp_send_ct *ct = &gpn_ft->ct;
        struct scatterlist *sg = gpn_ft->sg_resp;
@@ -595,7 +613,7 @@ static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries)
                return -E2BIG;
        }
 
-       down(&zfcp_data.config_sema);
+       mutex_lock(&zfcp_data.config_mutex);
 
        /* first entry is the header */
        for (x = 1; x < max_entries && !last; x++) {
@@ -628,16 +646,16 @@ static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries)
 
        zfcp_erp_wait(adapter);
        list_for_each_entry_safe(port, tmp, &adapter->port_list_head, list)
-               zfcp_validate_port(port);
-       up(&zfcp_data.config_sema);
+               zfcp_fc_validate_port(port);
+       mutex_unlock(&zfcp_data.config_mutex);
        return ret;
 }
 
 /**
- * zfcp_scan_ports - scan remote ports and attach new ports
+ * zfcp_fc_scan_ports - scan remote ports and attach new ports
  * @adapter: pointer to struct zfcp_adapter
  */
-int zfcp_scan_ports(struct zfcp_adapter *adapter)
+int zfcp_fc_scan_ports(struct zfcp_adapter *adapter)
 {
        int ret, i;
        struct zfcp_gpn_ft *gpn_ft;
@@ -652,7 +670,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->gs->ds);
+       ret = zfcp_fc_wka_port_get(&adapter->gs->ds);
        if (ret)
                return ret;
 
@@ -663,9 +681,9 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter)
        }
 
        for (i = 0; i < 3; i++) {
-               ret = zfcp_scan_issue_gpn_ft(gpn_ft, adapter, max_bytes);
+               ret = zfcp_fc_send_gpn_ft(gpn_ft, adapter, max_bytes);
                if (!ret) {
-                       ret = zfcp_scan_eval_gpn_ft(gpn_ft, max_entries);
+                       ret = zfcp_fc_eval_gpn_ft(gpn_ft, max_entries);
                        if (ret == -EAGAIN)
                                ssleep(1);
                        else
@@ -674,14 +692,14 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter)
        }
        zfcp_free_sg_env(gpn_ft, buf_num);
 out:
-       zfcp_wka_port_put(&adapter->gs->ds);
+       zfcp_fc_wka_port_put(&adapter->gs->ds);
        return ret;
 }
 
 
-void _zfcp_scan_ports_later(struct work_struct *work)
+void _zfcp_fc_scan_ports_later(struct work_struct *work)
 {
-       zfcp_scan_ports(container_of(work, struct zfcp_adapter, scan_work));
+       zfcp_fc_scan_ports(container_of(work, struct zfcp_adapter, scan_work));
 }
 
 struct zfcp_els_fc_job {
@@ -732,7 +750,7 @@ int zfcp_fc_execute_els_fc_job(struct fc_bsg_job *job)
        els_fc_job->els.adapter = adapter;
        if (rport) {
                read_lock_irq(&zfcp_data.config_lock);
-               port = rport->dd_data;
+               port = zfcp_get_port_by_wwpn(adapter, rport->port_name);
                if (port)
                        els_fc_job->els.d_id = port->d_id;
                read_unlock_irq(&zfcp_data.config_lock);
@@ -771,7 +789,7 @@ static void zfcp_fc_generic_ct_handler(unsigned long data)
        job->state_flags = FC_RQST_STATE_DONE;
        job->job_done(job);
 
-       zfcp_wka_port_put(ct_fc_job->ct.wka_port);
+       zfcp_fc_wka_port_put(ct_fc_job->ct.wka_port);
 
        kfree(ct_fc_job);
 }
@@ -817,7 +835,7 @@ int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *job)
                return -EINVAL; /* no such service */
        }
 
-       ret = zfcp_wka_port_get(ct_fc_job->ct.wka_port);
+       ret = zfcp_fc_wka_port_get(ct_fc_job->ct.wka_port);
        if (ret) {
                kfree(ct_fc_job);
                return ret;
@@ -825,16 +843,40 @@ int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *job)
 
        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);
+       ret = zfcp_fsf_send_ct(&ct_fc_job->ct, NULL);
        if (ret) {
                kfree(ct_fc_job);
-               zfcp_wka_port_put(ct_fc_job->ct.wka_port);
+               zfcp_fc_wka_port_put(ct_fc_job->ct.wka_port);
        }
        return ret;
 }
+
+int zfcp_fc_gs_setup(struct zfcp_adapter *adapter)
+{
+       struct zfcp_wka_ports *wka_ports;
+
+       wka_ports = kzalloc(sizeof(struct zfcp_wka_ports), GFP_KERNEL);
+       if (!wka_ports)
+               return -ENOMEM;
+
+       adapter->gs = wka_ports;
+       zfcp_fc_wka_port_init(&wka_ports->ms, FC_FID_MGMT_SERV, adapter);
+       zfcp_fc_wka_port_init(&wka_ports->ts, FC_FID_TIME_SERV, adapter);
+       zfcp_fc_wka_port_init(&wka_ports->ds, FC_FID_DIR_SERV, adapter);
+       zfcp_fc_wka_port_init(&wka_ports->as, FC_FID_ALIASES, adapter);
+       zfcp_fc_wka_port_init(&wka_ports->ks, FC_FID_SEC_KEY, adapter);
+
+       return 0;
+}
+
+void zfcp_fc_gs_destroy(struct zfcp_adapter *adapter)
+{
+       kfree(adapter->gs);
+       adapter->gs = NULL;
+}
+