diff options
Diffstat (limited to 'drivers/scsi/libfc/fc_rport.c')
-rw-r--r-- | drivers/scsi/libfc/fc_rport.c | 191 |
1 files changed, 155 insertions, 36 deletions
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index a7175adab32..49e1ccca09d 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c | |||
@@ -58,7 +58,7 @@ | |||
58 | 58 | ||
59 | #include "fc_libfc.h" | 59 | #include "fc_libfc.h" |
60 | 60 | ||
61 | struct workqueue_struct *rport_event_queue; | 61 | static struct workqueue_struct *rport_event_queue; |
62 | 62 | ||
63 | static void fc_rport_enter_flogi(struct fc_rport_priv *); | 63 | static void fc_rport_enter_flogi(struct fc_rport_priv *); |
64 | static void fc_rport_enter_plogi(struct fc_rport_priv *); | 64 | static void fc_rport_enter_plogi(struct fc_rport_priv *); |
@@ -145,8 +145,10 @@ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, | |||
145 | rdata->maxframe_size = FC_MIN_MAX_PAYLOAD; | 145 | rdata->maxframe_size = FC_MIN_MAX_PAYLOAD; |
146 | INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout); | 146 | INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout); |
147 | INIT_WORK(&rdata->event_work, fc_rport_work); | 147 | INIT_WORK(&rdata->event_work, fc_rport_work); |
148 | if (port_id != FC_FID_DIR_SERV) | 148 | if (port_id != FC_FID_DIR_SERV) { |
149 | rdata->lld_event_callback = lport->tt.rport_event_callback; | ||
149 | list_add_rcu(&rdata->peers, &lport->disc.rports); | 150 | list_add_rcu(&rdata->peers, &lport->disc.rports); |
151 | } | ||
150 | return rdata; | 152 | return rdata; |
151 | } | 153 | } |
152 | 154 | ||
@@ -257,6 +259,8 @@ static void fc_rport_work(struct work_struct *work) | |||
257 | struct fc_rport_operations *rport_ops; | 259 | struct fc_rport_operations *rport_ops; |
258 | struct fc_rport_identifiers ids; | 260 | struct fc_rport_identifiers ids; |
259 | struct fc_rport *rport; | 261 | struct fc_rport *rport; |
262 | struct fc4_prov *prov; | ||
263 | u8 type; | ||
260 | 264 | ||
261 | mutex_lock(&rdata->rp_mutex); | 265 | mutex_lock(&rdata->rp_mutex); |
262 | event = rdata->event; | 266 | event = rdata->event; |
@@ -300,12 +304,25 @@ static void fc_rport_work(struct work_struct *work) | |||
300 | FC_RPORT_DBG(rdata, "callback ev %d\n", event); | 304 | FC_RPORT_DBG(rdata, "callback ev %d\n", event); |
301 | rport_ops->event_callback(lport, rdata, event); | 305 | rport_ops->event_callback(lport, rdata, event); |
302 | } | 306 | } |
307 | if (rdata->lld_event_callback) { | ||
308 | FC_RPORT_DBG(rdata, "lld callback ev %d\n", event); | ||
309 | rdata->lld_event_callback(lport, rdata, event); | ||
310 | } | ||
303 | kref_put(&rdata->kref, lport->tt.rport_destroy); | 311 | kref_put(&rdata->kref, lport->tt.rport_destroy); |
304 | break; | 312 | break; |
305 | 313 | ||
306 | case RPORT_EV_FAILED: | 314 | case RPORT_EV_FAILED: |
307 | case RPORT_EV_LOGO: | 315 | case RPORT_EV_LOGO: |
308 | case RPORT_EV_STOP: | 316 | case RPORT_EV_STOP: |
317 | if (rdata->prli_count) { | ||
318 | mutex_lock(&fc_prov_mutex); | ||
319 | for (type = 1; type < FC_FC4_PROV_SIZE; type++) { | ||
320 | prov = fc_passive_prov[type]; | ||
321 | if (prov && prov->prlo) | ||
322 | prov->prlo(rdata); | ||
323 | } | ||
324 | mutex_unlock(&fc_prov_mutex); | ||
325 | } | ||
309 | port_id = rdata->ids.port_id; | 326 | port_id = rdata->ids.port_id; |
310 | mutex_unlock(&rdata->rp_mutex); | 327 | mutex_unlock(&rdata->rp_mutex); |
311 | 328 | ||
@@ -313,6 +330,10 @@ static void fc_rport_work(struct work_struct *work) | |||
313 | FC_RPORT_DBG(rdata, "callback ev %d\n", event); | 330 | FC_RPORT_DBG(rdata, "callback ev %d\n", event); |
314 | rport_ops->event_callback(lport, rdata, event); | 331 | rport_ops->event_callback(lport, rdata, event); |
315 | } | 332 | } |
333 | if (rdata->lld_event_callback) { | ||
334 | FC_RPORT_DBG(rdata, "lld callback ev %d\n", event); | ||
335 | rdata->lld_event_callback(lport, rdata, event); | ||
336 | } | ||
316 | cancel_delayed_work_sync(&rdata->retry_work); | 337 | cancel_delayed_work_sync(&rdata->retry_work); |
317 | 338 | ||
318 | /* | 339 | /* |
@@ -336,6 +357,7 @@ static void fc_rport_work(struct work_struct *work) | |||
336 | if (port_id == FC_FID_DIR_SERV) { | 357 | if (port_id == FC_FID_DIR_SERV) { |
337 | rdata->event = RPORT_EV_NONE; | 358 | rdata->event = RPORT_EV_NONE; |
338 | mutex_unlock(&rdata->rp_mutex); | 359 | mutex_unlock(&rdata->rp_mutex); |
360 | kref_put(&rdata->kref, lport->tt.rport_destroy); | ||
339 | } else if ((rdata->flags & FC_RP_STARTED) && | 361 | } else if ((rdata->flags & FC_RP_STARTED) && |
340 | rdata->major_retries < | 362 | rdata->major_retries < |
341 | lport->max_rport_retry_count) { | 363 | lport->max_rport_retry_count) { |
@@ -575,7 +597,7 @@ static void fc_rport_error_retry(struct fc_rport_priv *rdata, | |||
575 | 597 | ||
576 | /* make sure this isn't an FC_EX_CLOSED error, never retry those */ | 598 | /* make sure this isn't an FC_EX_CLOSED error, never retry those */ |
577 | if (PTR_ERR(fp) == -FC_EX_CLOSED) | 599 | if (PTR_ERR(fp) == -FC_EX_CLOSED) |
578 | return fc_rport_error(rdata, fp); | 600 | goto out; |
579 | 601 | ||
580 | if (rdata->retries < rdata->local_port->max_rport_retry_count) { | 602 | if (rdata->retries < rdata->local_port->max_rport_retry_count) { |
581 | FC_RPORT_DBG(rdata, "Error %ld in state %s, retrying\n", | 603 | FC_RPORT_DBG(rdata, "Error %ld in state %s, retrying\n", |
@@ -588,7 +610,8 @@ static void fc_rport_error_retry(struct fc_rport_priv *rdata, | |||
588 | return; | 610 | return; |
589 | } | 611 | } |
590 | 612 | ||
591 | return fc_rport_error(rdata, fp); | 613 | out: |
614 | fc_rport_error(rdata, fp); | ||
592 | } | 615 | } |
593 | 616 | ||
594 | /** | 617 | /** |
@@ -878,6 +901,9 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
878 | rdata->ids.port_name = get_unaligned_be64(&plp->fl_wwpn); | 901 | rdata->ids.port_name = get_unaligned_be64(&plp->fl_wwpn); |
879 | rdata->ids.node_name = get_unaligned_be64(&plp->fl_wwnn); | 902 | rdata->ids.node_name = get_unaligned_be64(&plp->fl_wwnn); |
880 | 903 | ||
904 | /* save plogi response sp_features for further reference */ | ||
905 | rdata->sp_features = ntohs(plp->fl_csp.sp_features); | ||
906 | |||
881 | if (lport->point_to_multipoint) | 907 | if (lport->point_to_multipoint) |
882 | fc_rport_login_complete(rdata, fp); | 908 | fc_rport_login_complete(rdata, fp); |
883 | csp_seq = ntohs(plp->fl_csp.sp_tot_seq); | 909 | csp_seq = ntohs(plp->fl_csp.sp_tot_seq); |
@@ -949,6 +975,8 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
949 | struct fc_els_prli prli; | 975 | struct fc_els_prli prli; |
950 | struct fc_els_spp spp; | 976 | struct fc_els_spp spp; |
951 | } *pp; | 977 | } *pp; |
978 | struct fc_els_spp temp_spp; | ||
979 | struct fc4_prov *prov; | ||
952 | u32 roles = FC_RPORT_ROLE_UNKNOWN; | 980 | u32 roles = FC_RPORT_ROLE_UNKNOWN; |
953 | u32 fcp_parm = 0; | 981 | u32 fcp_parm = 0; |
954 | u8 op; | 982 | u8 op; |
@@ -983,6 +1011,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
983 | resp_code = (pp->spp.spp_flags & FC_SPP_RESP_MASK); | 1011 | resp_code = (pp->spp.spp_flags & FC_SPP_RESP_MASK); |
984 | FC_RPORT_DBG(rdata, "PRLI spp_flags = 0x%x\n", | 1012 | FC_RPORT_DBG(rdata, "PRLI spp_flags = 0x%x\n", |
985 | pp->spp.spp_flags); | 1013 | pp->spp.spp_flags); |
1014 | rdata->spp_type = pp->spp.spp_type; | ||
986 | if (resp_code != FC_SPP_RESP_ACK) { | 1015 | if (resp_code != FC_SPP_RESP_ACK) { |
987 | if (resp_code == FC_SPP_RESP_CONF) | 1016 | if (resp_code == FC_SPP_RESP_CONF) |
988 | fc_rport_error(rdata, fp); | 1017 | fc_rport_error(rdata, fp); |
@@ -996,6 +1025,15 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
996 | fcp_parm = ntohl(pp->spp.spp_params); | 1025 | fcp_parm = ntohl(pp->spp.spp_params); |
997 | if (fcp_parm & FCP_SPPF_RETRY) | 1026 | if (fcp_parm & FCP_SPPF_RETRY) |
998 | rdata->flags |= FC_RP_FLAGS_RETRY; | 1027 | rdata->flags |= FC_RP_FLAGS_RETRY; |
1028 | if (fcp_parm & FCP_SPPF_CONF_COMPL) | ||
1029 | rdata->flags |= FC_RP_FLAGS_CONF_REQ; | ||
1030 | |||
1031 | prov = fc_passive_prov[FC_TYPE_FCP]; | ||
1032 | if (prov) { | ||
1033 | memset(&temp_spp, 0, sizeof(temp_spp)); | ||
1034 | prov->prli(rdata, pp->prli.prli_spp_len, | ||
1035 | &pp->spp, &temp_spp); | ||
1036 | } | ||
999 | 1037 | ||
1000 | rdata->supported_classes = FC_COS_CLASS3; | 1038 | rdata->supported_classes = FC_COS_CLASS3; |
1001 | if (fcp_parm & FCP_SPPF_INIT_FCN) | 1039 | if (fcp_parm & FCP_SPPF_INIT_FCN) |
@@ -1033,6 +1071,7 @@ static void fc_rport_enter_prli(struct fc_rport_priv *rdata) | |||
1033 | struct fc_els_spp spp; | 1071 | struct fc_els_spp spp; |
1034 | } *pp; | 1072 | } *pp; |
1035 | struct fc_frame *fp; | 1073 | struct fc_frame *fp; |
1074 | struct fc4_prov *prov; | ||
1036 | 1075 | ||
1037 | /* | 1076 | /* |
1038 | * If the rport is one of the well known addresses | 1077 | * If the rport is one of the well known addresses |
@@ -1054,9 +1093,20 @@ static void fc_rport_enter_prli(struct fc_rport_priv *rdata) | |||
1054 | return; | 1093 | return; |
1055 | } | 1094 | } |
1056 | 1095 | ||
1057 | if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PRLI, | 1096 | fc_prli_fill(lport, fp); |
1058 | fc_rport_prli_resp, rdata, | 1097 | |
1059 | 2 * lport->r_a_tov)) | 1098 | prov = fc_passive_prov[FC_TYPE_FCP]; |
1099 | if (prov) { | ||
1100 | pp = fc_frame_payload_get(fp, sizeof(*pp)); | ||
1101 | prov->prli(rdata, sizeof(pp->spp), NULL, &pp->spp); | ||
1102 | } | ||
1103 | |||
1104 | fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, rdata->ids.port_id, | ||
1105 | fc_host_port_id(lport->host), FC_TYPE_ELS, | ||
1106 | FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); | ||
1107 | |||
1108 | if (!lport->tt.exch_seq_send(lport, fp, fc_rport_prli_resp, | ||
1109 | NULL, rdata, 2 * lport->r_a_tov)) | ||
1060 | fc_rport_error_retry(rdata, NULL); | 1110 | fc_rport_error_retry(rdata, NULL); |
1061 | else | 1111 | else |
1062 | kref_get(&rdata->kref); | 1112 | kref_get(&rdata->kref); |
@@ -1642,9 +1692,9 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, | |||
1642 | unsigned int len; | 1692 | unsigned int len; |
1643 | unsigned int plen; | 1693 | unsigned int plen; |
1644 | enum fc_els_spp_resp resp; | 1694 | enum fc_els_spp_resp resp; |
1695 | enum fc_els_spp_resp passive; | ||
1645 | struct fc_seq_els_data rjt_data; | 1696 | struct fc_seq_els_data rjt_data; |
1646 | u32 fcp_parm; | 1697 | struct fc4_prov *prov; |
1647 | u32 roles = FC_RPORT_ROLE_UNKNOWN; | ||
1648 | 1698 | ||
1649 | FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n", | 1699 | FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n", |
1650 | fc_rport_state(rdata)); | 1700 | fc_rport_state(rdata)); |
@@ -1678,46 +1728,42 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, | |||
1678 | pp->prli.prli_len = htons(len); | 1728 | pp->prli.prli_len = htons(len); |
1679 | len -= sizeof(struct fc_els_prli); | 1729 | len -= sizeof(struct fc_els_prli); |
1680 | 1730 | ||
1681 | /* reinitialize remote port roles */ | ||
1682 | rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN; | ||
1683 | |||
1684 | /* | 1731 | /* |
1685 | * Go through all the service parameter pages and build | 1732 | * Go through all the service parameter pages and build |
1686 | * response. If plen indicates longer SPP than standard, | 1733 | * response. If plen indicates longer SPP than standard, |
1687 | * use that. The entire response has been pre-cleared above. | 1734 | * use that. The entire response has been pre-cleared above. |
1688 | */ | 1735 | */ |
1689 | spp = &pp->spp; | 1736 | spp = &pp->spp; |
1737 | mutex_lock(&fc_prov_mutex); | ||
1690 | while (len >= plen) { | 1738 | while (len >= plen) { |
1739 | rdata->spp_type = rspp->spp_type; | ||
1691 | spp->spp_type = rspp->spp_type; | 1740 | spp->spp_type = rspp->spp_type; |
1692 | spp->spp_type_ext = rspp->spp_type_ext; | 1741 | spp->spp_type_ext = rspp->spp_type_ext; |
1693 | spp->spp_flags = rspp->spp_flags & FC_SPP_EST_IMG_PAIR; | 1742 | resp = 0; |
1694 | resp = FC_SPP_RESP_ACK; | 1743 | |
1695 | 1744 | if (rspp->spp_type < FC_FC4_PROV_SIZE) { | |
1696 | switch (rspp->spp_type) { | 1745 | prov = fc_active_prov[rspp->spp_type]; |
1697 | case 0: /* common to all FC-4 types */ | 1746 | if (prov) |
1698 | break; | 1747 | resp = prov->prli(rdata, plen, rspp, spp); |
1699 | case FC_TYPE_FCP: | 1748 | prov = fc_passive_prov[rspp->spp_type]; |
1700 | fcp_parm = ntohl(rspp->spp_params); | 1749 | if (prov) { |
1701 | if (fcp_parm & FCP_SPPF_RETRY) | 1750 | passive = prov->prli(rdata, plen, rspp, spp); |
1702 | rdata->flags |= FC_RP_FLAGS_RETRY; | 1751 | if (!resp || passive == FC_SPP_RESP_ACK) |
1703 | rdata->supported_classes = FC_COS_CLASS3; | 1752 | resp = passive; |
1704 | if (fcp_parm & FCP_SPPF_INIT_FCN) | 1753 | } |
1705 | roles |= FC_RPORT_ROLE_FCP_INITIATOR; | 1754 | } |
1706 | if (fcp_parm & FCP_SPPF_TARG_FCN) | 1755 | if (!resp) { |
1707 | roles |= FC_RPORT_ROLE_FCP_TARGET; | 1756 | if (spp->spp_flags & FC_SPP_EST_IMG_PAIR) |
1708 | rdata->ids.roles = roles; | 1757 | resp |= FC_SPP_RESP_CONF; |
1709 | 1758 | else | |
1710 | spp->spp_params = htonl(lport->service_params); | 1759 | resp |= FC_SPP_RESP_INVL; |
1711 | break; | ||
1712 | default: | ||
1713 | resp = FC_SPP_RESP_INVL; | ||
1714 | break; | ||
1715 | } | 1760 | } |
1716 | spp->spp_flags |= resp; | 1761 | spp->spp_flags |= resp; |
1717 | len -= plen; | 1762 | len -= plen; |
1718 | rspp = (struct fc_els_spp *)((char *)rspp + plen); | 1763 | rspp = (struct fc_els_spp *)((char *)rspp + plen); |
1719 | spp = (struct fc_els_spp *)((char *)spp + plen); | 1764 | spp = (struct fc_els_spp *)((char *)spp + plen); |
1720 | } | 1765 | } |
1766 | mutex_unlock(&fc_prov_mutex); | ||
1721 | 1767 | ||
1722 | /* | 1768 | /* |
1723 | * Send LS_ACC. If this fails, the originator should retry. | 1769 | * Send LS_ACC. If this fails, the originator should retry. |
@@ -1887,9 +1933,82 @@ int fc_rport_init(struct fc_lport *lport) | |||
1887 | EXPORT_SYMBOL(fc_rport_init); | 1933 | EXPORT_SYMBOL(fc_rport_init); |
1888 | 1934 | ||
1889 | /** | 1935 | /** |
1936 | * fc_rport_fcp_prli() - Handle incoming PRLI for the FCP initiator. | ||
1937 | * @rdata: remote port private | ||
1938 | * @spp_len: service parameter page length | ||
1939 | * @rspp: received service parameter page | ||
1940 | * @spp: response service parameter page | ||
1941 | * | ||
1942 | * Returns the value for the response code to be placed in spp_flags; | ||
1943 | * Returns 0 if not an initiator. | ||
1944 | */ | ||
1945 | static int fc_rport_fcp_prli(struct fc_rport_priv *rdata, u32 spp_len, | ||
1946 | const struct fc_els_spp *rspp, | ||
1947 | struct fc_els_spp *spp) | ||
1948 | { | ||
1949 | struct fc_lport *lport = rdata->local_port; | ||
1950 | u32 fcp_parm; | ||
1951 | |||
1952 | fcp_parm = ntohl(rspp->spp_params); | ||
1953 | rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN; | ||
1954 | if (fcp_parm & FCP_SPPF_INIT_FCN) | ||
1955 | rdata->ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR; | ||
1956 | if (fcp_parm & FCP_SPPF_TARG_FCN) | ||
1957 | rdata->ids.roles |= FC_RPORT_ROLE_FCP_TARGET; | ||
1958 | if (fcp_parm & FCP_SPPF_RETRY) | ||
1959 | rdata->flags |= FC_RP_FLAGS_RETRY; | ||
1960 | rdata->supported_classes = FC_COS_CLASS3; | ||
1961 | |||
1962 | if (!(lport->service_params & FC_RPORT_ROLE_FCP_INITIATOR)) | ||
1963 | return 0; | ||
1964 | |||
1965 | spp->spp_flags |= rspp->spp_flags & FC_SPP_EST_IMG_PAIR; | ||
1966 | |||
1967 | /* | ||
1968 | * OR in our service parameters with other providers (target), if any. | ||
1969 | */ | ||
1970 | fcp_parm = ntohl(spp->spp_params); | ||
1971 | spp->spp_params = htonl(fcp_parm | lport->service_params); | ||
1972 | return FC_SPP_RESP_ACK; | ||
1973 | } | ||
1974 | |||
1975 | /* | ||
1976 | * FC-4 provider ops for FCP initiator. | ||
1977 | */ | ||
1978 | struct fc4_prov fc_rport_fcp_init = { | ||
1979 | .prli = fc_rport_fcp_prli, | ||
1980 | }; | ||
1981 | |||
1982 | /** | ||
1983 | * fc_rport_t0_prli() - Handle incoming PRLI parameters for type 0 | ||
1984 | * @rdata: remote port private | ||
1985 | * @spp_len: service parameter page length | ||
1986 | * @rspp: received service parameter page | ||
1987 | * @spp: response service parameter page | ||
1988 | */ | ||
1989 | static int fc_rport_t0_prli(struct fc_rport_priv *rdata, u32 spp_len, | ||
1990 | const struct fc_els_spp *rspp, | ||
1991 | struct fc_els_spp *spp) | ||
1992 | { | ||
1993 | if (rspp->spp_flags & FC_SPP_EST_IMG_PAIR) | ||
1994 | return FC_SPP_RESP_INVL; | ||
1995 | return FC_SPP_RESP_ACK; | ||
1996 | } | ||
1997 | |||
1998 | /* | ||
1999 | * FC-4 provider ops for type 0 service parameters. | ||
2000 | * | ||
2001 | * This handles the special case of type 0 which is always successful | ||
2002 | * but doesn't do anything otherwise. | ||
2003 | */ | ||
2004 | struct fc4_prov fc_rport_t0_prov = { | ||
2005 | .prli = fc_rport_t0_prli, | ||
2006 | }; | ||
2007 | |||
2008 | /** | ||
1890 | * fc_setup_rport() - Initialize the rport_event_queue | 2009 | * fc_setup_rport() - Initialize the rport_event_queue |
1891 | */ | 2010 | */ |
1892 | int fc_setup_rport() | 2011 | int fc_setup_rport(void) |
1893 | { | 2012 | { |
1894 | rport_event_queue = create_singlethread_workqueue("fc_rport_eq"); | 2013 | rport_event_queue = create_singlethread_workqueue("fc_rport_eq"); |
1895 | if (!rport_event_queue) | 2014 | if (!rport_event_queue) |
@@ -1900,7 +2019,7 @@ int fc_setup_rport() | |||
1900 | /** | 2019 | /** |
1901 | * fc_destroy_rport() - Destroy the rport_event_queue | 2020 | * fc_destroy_rport() - Destroy the rport_event_queue |
1902 | */ | 2021 | */ |
1903 | void fc_destroy_rport() | 2022 | void fc_destroy_rport(void) |
1904 | { | 2023 | { |
1905 | destroy_workqueue(rport_event_queue); | 2024 | destroy_workqueue(rport_event_queue); |
1906 | } | 2025 | } |