aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libfc
diff options
context:
space:
mode:
authorNeerav Parikh <neerav.parikh@intel.com>2012-01-22 20:30:05 -0500
committerJames Bottomley <JBottomley@Parallels.com>2012-02-19 09:08:58 -0500
commitd78c317f6cd701bda9f6dbfbfbcba72f39dd6ad7 (patch)
tree54ae30e3856fd44b2d5629300517041d79528651 /drivers/scsi/libfc
parent1ea2c1daf4476ac798b1de8196f11dd36425b5ae (diff)
[SCSI] libfc: Add support for FDMI
This patch adds support for Fabric Device Management Interface as per FC-GS-4 spec. in libfc. Any driver making use of libfc can enable fdmi state machine for a given lport. If lport has enabled FDMI support the lport state machine will transition into FDMI after completing the DNS states and before entering the SCR state. The FDMI state transition is such that if there is an error, it won't stop the lport state machine from transitioning and the it will behave as if there was no FDMI support. The FDMI HBA attributes are registed with the Management server via Register HBA (RHBA) command and the port attributes are reigstered using the Register Port(RPA) command. Signed-off-by: Neerav Parikh <neerav.parikh@intel.com> Tested-by: Ross Brattain <ross.b.brattain@intel.com> Acked-by: Robert Love <robert.w.love@intel.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/libfc')
-rw-r--r--drivers/scsi/libfc/fc_lport.c227
1 files changed, 224 insertions, 3 deletions
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index 83750ebb527f..9a0b2a9caad6 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -116,6 +116,8 @@ static void fc_lport_enter_ns(struct fc_lport *, enum fc_lport_state);
116static void fc_lport_enter_scr(struct fc_lport *); 116static void fc_lport_enter_scr(struct fc_lport *);
117static void fc_lport_enter_ready(struct fc_lport *); 117static void fc_lport_enter_ready(struct fc_lport *);
118static void fc_lport_enter_logo(struct fc_lport *); 118static void fc_lport_enter_logo(struct fc_lport *);
119static void fc_lport_enter_fdmi(struct fc_lport *lport);
120static void fc_lport_enter_ms(struct fc_lport *, enum fc_lport_state);
119 121
120static const char *fc_lport_state_names[] = { 122static const char *fc_lport_state_names[] = {
121 [LPORT_ST_DISABLED] = "disabled", 123 [LPORT_ST_DISABLED] = "disabled",
@@ -126,6 +128,11 @@ static const char *fc_lport_state_names[] = {
126 [LPORT_ST_RSPN_ID] = "RSPN_ID", 128 [LPORT_ST_RSPN_ID] = "RSPN_ID",
127 [LPORT_ST_RFT_ID] = "RFT_ID", 129 [LPORT_ST_RFT_ID] = "RFT_ID",
128 [LPORT_ST_RFF_ID] = "RFF_ID", 130 [LPORT_ST_RFF_ID] = "RFF_ID",
131 [LPORT_ST_FDMI] = "FDMI",
132 [LPORT_ST_RHBA] = "RHBA",
133 [LPORT_ST_RPA] = "RPA",
134 [LPORT_ST_DHBA] = "DHBA",
135 [LPORT_ST_DPRT] = "DPRT",
129 [LPORT_ST_SCR] = "SCR", 136 [LPORT_ST_SCR] = "SCR",
130 [LPORT_ST_READY] = "Ready", 137 [LPORT_ST_READY] = "Ready",
131 [LPORT_ST_LOGO] = "LOGO", 138 [LPORT_ST_LOGO] = "LOGO",
@@ -183,11 +190,14 @@ static void fc_lport_rport_callback(struct fc_lport *lport,
183 if (lport->state == LPORT_ST_DNS) { 190 if (lport->state == LPORT_ST_DNS) {
184 lport->dns_rdata = rdata; 191 lport->dns_rdata = rdata;
185 fc_lport_enter_ns(lport, LPORT_ST_RNN_ID); 192 fc_lport_enter_ns(lport, LPORT_ST_RNN_ID);
193 } else if (lport->state == LPORT_ST_FDMI) {
194 lport->ms_rdata = rdata;
195 fc_lport_enter_ms(lport, LPORT_ST_DHBA);
186 } else { 196 } else {
187 FC_LPORT_DBG(lport, "Received an READY event " 197 FC_LPORT_DBG(lport, "Received an READY event "
188 "on port (%6.6x) for the directory " 198 "on port (%6.6x) for the directory "
189 "server, but the lport is not " 199 "server, but the lport is not "
190 "in the DNS state, it's in the " 200 "in the DNS or FDMI state, it's in the "
191 "%d state", rdata->ids.port_id, 201 "%d state", rdata->ids.port_id,
192 lport->state); 202 lport->state);
193 lport->tt.rport_logoff(rdata); 203 lport->tt.rport_logoff(rdata);
@@ -196,7 +206,10 @@ static void fc_lport_rport_callback(struct fc_lport *lport,
196 case RPORT_EV_LOGO: 206 case RPORT_EV_LOGO:
197 case RPORT_EV_FAILED: 207 case RPORT_EV_FAILED:
198 case RPORT_EV_STOP: 208 case RPORT_EV_STOP:
199 lport->dns_rdata = NULL; 209 if (rdata->ids.port_id == FC_FID_DIR_SERV)
210 lport->dns_rdata = NULL;
211 else if (rdata->ids.port_id == FC_FID_MGMT_SERV)
212 lport->ms_rdata = NULL;
200 break; 213 break;
201 case RPORT_EV_NONE: 214 case RPORT_EV_NONE:
202 break; 215 break;
@@ -1148,7 +1161,10 @@ static void fc_lport_ns_resp(struct fc_seq *sp, struct fc_frame *fp,
1148 fc_lport_enter_ns(lport, LPORT_ST_RFF_ID); 1161 fc_lport_enter_ns(lport, LPORT_ST_RFF_ID);
1149 break; 1162 break;
1150 case LPORT_ST_RFF_ID: 1163 case LPORT_ST_RFF_ID:
1151 fc_lport_enter_scr(lport); 1164 if (lport->fdmi_enabled)
1165 fc_lport_enter_fdmi(lport);
1166 else
1167 fc_lport_enter_scr(lport);
1152 break; 1168 break;
1153 default: 1169 default:
1154 /* should have already been caught by state checks */ 1170 /* should have already been caught by state checks */
@@ -1163,6 +1179,85 @@ err:
1163} 1179}
1164 1180
1165/** 1181/**
1182 * fc_lport_ms_resp() - Handle response to a management server
1183 * exchange
1184 * @sp: current sequence in exchange
1185 * @fp: response frame
1186 * @lp_arg: Fibre Channel host port instance
1187 *
1188 * Locking Note: This function will be called without the lport lock
1189 * held, but it will lock, call an _enter_* function or fc_lport_error()
1190 * and then unlock the lport.
1191 */
1192static void fc_lport_ms_resp(struct fc_seq *sp, struct fc_frame *fp,
1193 void *lp_arg)
1194{
1195 struct fc_lport *lport = lp_arg;
1196 struct fc_frame_header *fh;
1197 struct fc_ct_hdr *ct;
1198
1199 FC_LPORT_DBG(lport, "Received a ms %s\n", fc_els_resp_type(fp));
1200
1201 if (fp == ERR_PTR(-FC_EX_CLOSED))
1202 return;
1203
1204 mutex_lock(&lport->lp_mutex);
1205
1206 if (lport->state < LPORT_ST_RHBA || lport->state > LPORT_ST_DPRT) {
1207 FC_LPORT_DBG(lport, "Received a management server response, "
1208 "but in state %s\n", fc_lport_state(lport));
1209 if (IS_ERR(fp))
1210 goto err;
1211 goto out;
1212 }
1213
1214 if (IS_ERR(fp)) {
1215 fc_lport_error(lport, fp);
1216 goto err;
1217 }
1218
1219 fh = fc_frame_header_get(fp);
1220 ct = fc_frame_payload_get(fp, sizeof(*ct));
1221
1222 if (fh && ct && fh->fh_type == FC_TYPE_CT &&
1223 ct->ct_fs_type == FC_FST_MGMT &&
1224 ct->ct_fs_subtype == FC_FDMI_SUBTYPE) {
1225 FC_LPORT_DBG(lport, "Received a management server response, "
1226 "reason=%d explain=%d\n",
1227 ct->ct_reason,
1228 ct->ct_explan);
1229
1230 switch (lport->state) {
1231 case LPORT_ST_RHBA:
1232 if (ntohs(ct->ct_cmd) == FC_FS_ACC)
1233 fc_lport_enter_ms(lport, LPORT_ST_RPA);
1234 else /* Error Skip RPA */
1235 fc_lport_enter_scr(lport);
1236 break;
1237 case LPORT_ST_RPA:
1238 fc_lport_enter_scr(lport);
1239 break;
1240 case LPORT_ST_DPRT:
1241 fc_lport_enter_ms(lport, LPORT_ST_RHBA);
1242 break;
1243 case LPORT_ST_DHBA:
1244 fc_lport_enter_ms(lport, LPORT_ST_DPRT);
1245 break;
1246 default:
1247 /* should have already been caught by state checks */
1248 break;
1249 }
1250 } else {
1251 /* Invalid Frame? */
1252 fc_lport_error(lport, fp);
1253 }
1254out:
1255 fc_frame_free(fp);
1256err:
1257 mutex_unlock(&lport->lp_mutex);
1258}
1259
1260/**
1166 * fc_lport_scr_resp() - Handle response to State Change Register (SCR) request 1261 * fc_lport_scr_resp() - Handle response to State Change Register (SCR) request
1167 * @sp: current sequence in SCR exchange 1262 * @sp: current sequence in SCR exchange
1168 * @fp: response frame 1263 * @fp: response frame
@@ -1339,6 +1434,123 @@ err:
1339} 1434}
1340 1435
1341/** 1436/**
1437 * fc_lport_enter_ms() - management server commands
1438 * @lport: Fibre Channel local port to register
1439 *
1440 * Locking Note: The lport lock is expected to be held before calling
1441 * this routine.
1442 */
1443static void fc_lport_enter_ms(struct fc_lport *lport, enum fc_lport_state state)
1444{
1445 struct fc_frame *fp;
1446 enum fc_fdmi_req cmd;
1447 int size = sizeof(struct fc_ct_hdr);
1448 size_t len;
1449 int numattrs;
1450
1451 FC_LPORT_DBG(lport, "Entered %s state from %s state\n",
1452 fc_lport_state_names[state],
1453 fc_lport_state(lport));
1454
1455 fc_lport_state_enter(lport, state);
1456
1457 switch (state) {
1458 case LPORT_ST_RHBA:
1459 cmd = FC_FDMI_RHBA;
1460 /* Number of HBA Attributes */
1461 numattrs = 10;
1462 len = sizeof(struct fc_fdmi_rhba);
1463 len -= sizeof(struct fc_fdmi_attr_entry);
1464 len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN);
1465 len += FC_FDMI_HBA_ATTR_NODENAME_LEN;
1466 len += FC_FDMI_HBA_ATTR_MANUFACTURER_LEN;
1467 len += FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN;
1468 len += FC_FDMI_HBA_ATTR_MODEL_LEN;
1469 len += FC_FDMI_HBA_ATTR_MODELDESCR_LEN;
1470 len += FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN;
1471 len += FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN;
1472 len += FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN;
1473 len += FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN;
1474 len += FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN;
1475
1476 size += len;
1477 break;
1478 case LPORT_ST_RPA:
1479 cmd = FC_FDMI_RPA;
1480 /* Number of Port Attributes */
1481 numattrs = 6;
1482 len = sizeof(struct fc_fdmi_rpa);
1483 len -= sizeof(struct fc_fdmi_attr_entry);
1484 len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN);
1485 len += FC_FDMI_PORT_ATTR_FC4TYPES_LEN;
1486 len += FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN;
1487 len += FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN;
1488 len += FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN;
1489 len += FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN;
1490 len += FC_FDMI_PORT_ATTR_HOSTNAME_LEN;
1491
1492 size += len;
1493 break;
1494 case LPORT_ST_DPRT:
1495 cmd = FC_FDMI_DPRT;
1496 len = sizeof(struct fc_fdmi_dprt);
1497 size += len;
1498 break;
1499 case LPORT_ST_DHBA:
1500 cmd = FC_FDMI_DHBA;
1501 len = sizeof(struct fc_fdmi_dhba);
1502 size += len;
1503 break;
1504 default:
1505 fc_lport_error(lport, NULL);
1506 return;
1507 }
1508
1509 FC_LPORT_DBG(lport, "Cmd=0x%x Len %d size %d\n",
1510 cmd, (int)len, size);
1511 fp = fc_frame_alloc(lport, size);
1512 if (!fp) {
1513 fc_lport_error(lport, fp);
1514 return;
1515 }
1516
1517 if (!lport->tt.elsct_send(lport, FC_FID_MGMT_SERV, fp, cmd,
1518 fc_lport_ms_resp,
1519 lport, 3 * lport->r_a_tov))
1520 fc_lport_error(lport, fp);
1521}
1522
1523/**
1524 * fc_rport_enter_fdmi() - Create a fc_rport for the management server
1525 * @lport: The local port requesting a remote port for the management server
1526 *
1527 * Locking Note: The lport lock is expected to be held before calling
1528 * this routine.
1529 */
1530static void fc_lport_enter_fdmi(struct fc_lport *lport)
1531{
1532 struct fc_rport_priv *rdata;
1533
1534 FC_LPORT_DBG(lport, "Entered FDMI state from %s state\n",
1535 fc_lport_state(lport));
1536
1537 fc_lport_state_enter(lport, LPORT_ST_FDMI);
1538
1539 mutex_lock(&lport->disc.disc_mutex);
1540 rdata = lport->tt.rport_create(lport, FC_FID_MGMT_SERV);
1541 mutex_unlock(&lport->disc.disc_mutex);
1542 if (!rdata)
1543 goto err;
1544
1545 rdata->ops = &fc_lport_rport_ops;
1546 lport->tt.rport_login(rdata);
1547 return;
1548
1549err:
1550 fc_lport_error(lport, NULL);
1551}
1552
1553/**
1342 * fc_lport_timeout() - Handler for the retry_work timer 1554 * fc_lport_timeout() - Handler for the retry_work timer
1343 * @work: The work struct of the local port 1555 * @work: The work struct of the local port
1344 */ 1556 */
@@ -1371,6 +1583,15 @@ static void fc_lport_timeout(struct work_struct *work)
1371 case LPORT_ST_RFF_ID: 1583 case LPORT_ST_RFF_ID:
1372 fc_lport_enter_ns(lport, lport->state); 1584 fc_lport_enter_ns(lport, lport->state);
1373 break; 1585 break;
1586 case LPORT_ST_FDMI:
1587 fc_lport_enter_fdmi(lport);
1588 break;
1589 case LPORT_ST_RHBA:
1590 case LPORT_ST_RPA:
1591 case LPORT_ST_DHBA:
1592 case LPORT_ST_DPRT:
1593 fc_lport_enter_ms(lport, lport->state);
1594 break;
1374 case LPORT_ST_SCR: 1595 case LPORT_ST_SCR:
1375 fc_lport_enter_scr(lport); 1596 fc_lport_enter_scr(lport);
1376 break; 1597 break;