diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-22 15:55:29 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-22 15:55:29 -0400 |
commit | 424a6f6ef990b7e9f56f6627bfc6c46b493faeb4 (patch) | |
tree | 0028356ed8003495fbbe1f716f359e3c8ebc35b6 /drivers/scsi/libfc | |
parent | 1ab142d499294b844ecc81e8004db4ce029b0b61 (diff) | |
parent | cd8df932d894f3128c884e3ae1b2b484540513db (diff) |
Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
SCSI updates from James Bottomley:
"The update includes the usual assortment of driver updates (lpfc,
qla2xxx, qla4xxx, bfa, bnx2fc, bnx2i, isci, fcoe, hpsa) plus a huge
amount of infrastructure work in the SAS library and transport class
as well as an iSCSI update. There's also a new SCSI based virtio
driver."
* tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (177 commits)
[SCSI] qla4xxx: Update driver version to 5.02.00-k15
[SCSI] qla4xxx: trivial cleanup
[SCSI] qla4xxx: Fix sparse warning
[SCSI] qla4xxx: Add support for multiple session per host.
[SCSI] qla4xxx: Export CHAP index as sysfs attribute
[SCSI] scsi_transport: Export CHAP index as sysfs attribute
[SCSI] qla4xxx: Add support to display CHAP list and delete CHAP entry
[SCSI] iscsi_transport: Add support to display CHAP list and delete CHAP entry
[SCSI] pm8001: fix endian issue with code optimization.
[SCSI] pm8001: Fix possible racing condition.
[SCSI] pm8001: Fix bogus interrupt state flag issue.
[SCSI] ipr: update PCI ID definitions for new adapters
[SCSI] qla2xxx: handle default case in qla2x00_request_firmware()
[SCSI] isci: improvements in driver unloading routine
[SCSI] isci: improve phy event warnings
[SCSI] isci: debug, provide state-enum-to-string conversions
[SCSI] scsi_transport_sas: 'enable' phys on reset
[SCSI] libsas: don't recover end devices attached to disabled phys
[SCSI] libsas: fixup target_port_protocols for expanders that don't report sata
[SCSI] libsas: set attached device type and target protocols for local phys
...
Diffstat (limited to 'drivers/scsi/libfc')
-rw-r--r-- | drivers/scsi/libfc/fc_disc.c | 7 | ||||
-rw-r--r-- | drivers/scsi/libfc/fc_elsct.c | 3 | ||||
-rw-r--r-- | drivers/scsi/libfc/fc_exch.c | 7 | ||||
-rw-r--r-- | drivers/scsi/libfc/fc_lport.c | 227 |
4 files changed, 236 insertions, 8 deletions
diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 1d1b0c9da29b..8e561e6a557c 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c | |||
@@ -337,6 +337,13 @@ static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp) | |||
337 | schedule_delayed_work(&disc->disc_work, delay); | 337 | schedule_delayed_work(&disc->disc_work, delay); |
338 | } else | 338 | } else |
339 | fc_disc_done(disc, DISC_EV_FAILED); | 339 | fc_disc_done(disc, DISC_EV_FAILED); |
340 | } else if (PTR_ERR(fp) == -FC_EX_CLOSED) { | ||
341 | /* | ||
342 | * if discovery fails due to lport reset, clear | ||
343 | * pending flag so that subsequent discovery can | ||
344 | * continue | ||
345 | */ | ||
346 | disc->pending = 0; | ||
340 | } | 347 | } |
341 | } | 348 | } |
342 | 349 | ||
diff --git a/drivers/scsi/libfc/fc_elsct.c b/drivers/scsi/libfc/fc_elsct.c index e17a28d324d0..c2384d501470 100644 --- a/drivers/scsi/libfc/fc_elsct.c +++ b/drivers/scsi/libfc/fc_elsct.c | |||
@@ -56,8 +56,7 @@ struct fc_seq *fc_elsct_send(struct fc_lport *lport, u32 did, | |||
56 | rc = fc_els_fill(lport, did, fp, op, &r_ctl, &fh_type); | 56 | rc = fc_els_fill(lport, did, fp, op, &r_ctl, &fh_type); |
57 | else { | 57 | else { |
58 | /* CT requests */ | 58 | /* CT requests */ |
59 | rc = fc_ct_fill(lport, did, fp, op, &r_ctl, &fh_type); | 59 | rc = fc_ct_fill(lport, did, fp, op, &r_ctl, &fh_type, &did); |
60 | did = FC_FID_DIR_SERV; | ||
61 | } | 60 | } |
62 | 61 | ||
63 | if (rc) { | 62 | if (rc) { |
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 4d70d96fa5dc..630291f01826 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c | |||
@@ -1642,9 +1642,10 @@ static void fc_exch_recv_bls(struct fc_exch_mgr *mp, struct fc_frame *fp) | |||
1642 | case FC_RCTL_ACK_0: | 1642 | case FC_RCTL_ACK_0: |
1643 | break; | 1643 | break; |
1644 | default: | 1644 | default: |
1645 | FC_EXCH_DBG(ep, "BLS rctl %x - %s received", | 1645 | if (ep) |
1646 | fh->fh_r_ctl, | 1646 | FC_EXCH_DBG(ep, "BLS rctl %x - %s received", |
1647 | fc_exch_rctl_name(fh->fh_r_ctl)); | 1647 | fh->fh_r_ctl, |
1648 | fc_exch_rctl_name(fh->fh_r_ctl)); | ||
1648 | break; | 1649 | break; |
1649 | } | 1650 | } |
1650 | fc_frame_free(fp); | 1651 | fc_frame_free(fp); |
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index c1a808cc5920..bd5d31d022d9 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); | |||
116 | static void fc_lport_enter_scr(struct fc_lport *); | 116 | static void fc_lport_enter_scr(struct fc_lport *); |
117 | static void fc_lport_enter_ready(struct fc_lport *); | 117 | static void fc_lport_enter_ready(struct fc_lport *); |
118 | static void fc_lport_enter_logo(struct fc_lport *); | 118 | static void fc_lport_enter_logo(struct fc_lport *); |
119 | static void fc_lport_enter_fdmi(struct fc_lport *lport); | ||
120 | static void fc_lport_enter_ms(struct fc_lport *, enum fc_lport_state); | ||
119 | 121 | ||
120 | static const char *fc_lport_state_names[] = { | 122 | static 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 | */ | ||
1192 | static 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 | } | ||
1254 | out: | ||
1255 | fc_frame_free(fp); | ||
1256 | err: | ||
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 | */ | ||
1443 | static 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 | */ | ||
1530 | static 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 | |||
1549 | err: | ||
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; |