aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libfc/fc_rport.c
diff options
context:
space:
mode:
authorJoe Eykholt <jeykholt@cisco.com>2010-03-12 19:07:36 -0500
committerJames Bottomley <James.Bottomley@suse.de>2010-04-11 10:23:33 -0400
commita2f6a024e1a7ce37f424a567733501d98b8555d7 (patch)
treedf6fd29c5b7b8459077c09be3dac6829b22ae58a /drivers/scsi/libfc/fc_rport.c
parentfc193172e63af2c749e198816a1ee694dd6395e6 (diff)
[SCSI] libfc: recode incoming PRLI handling
Reduce indentation in fc_rport_recv_prli_req() using gotos. Also add payload length checks. Signed-off-by: Joe Eykholt <jeykholt@cisco.com> Signed-off-by: Robert Love <robert.w.love@intel.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/libfc/fc_rport.c')
-rw-r--r--drivers/scsi/libfc/fc_rport.c195
1 files changed, 87 insertions, 108 deletions
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index b37d0ff28b35..39e440f0f54a 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -1442,136 +1442,115 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
1442 struct fc_els_spp *spp; /* response spp */ 1442 struct fc_els_spp *spp; /* response spp */
1443 unsigned int len; 1443 unsigned int len;
1444 unsigned int plen; 1444 unsigned int plen;
1445 enum fc_els_rjt_reason reason = ELS_RJT_UNAB;
1446 enum fc_els_rjt_explan explan = ELS_EXPL_NONE;
1447 enum fc_els_spp_resp resp; 1445 enum fc_els_spp_resp resp;
1448 struct fc_seq_els_data rjt_data; 1446 struct fc_seq_els_data rjt_data;
1449 u32 f_ctl; 1447 u32 f_ctl;
1450 u32 fcp_parm; 1448 u32 fcp_parm;
1451 u32 roles = FC_RPORT_ROLE_UNKNOWN; 1449 u32 roles = FC_RPORT_ROLE_UNKNOWN;
1452 rjt_data.fp = NULL;
1453 1450
1451 rjt_data.fp = NULL;
1454 fh = fc_frame_header_get(rx_fp); 1452 fh = fc_frame_header_get(rx_fp);
1455 1453
1456 FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n", 1454 FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n",
1457 fc_rport_state(rdata)); 1455 fc_rport_state(rdata));
1458 1456
1459 switch (rdata->rp_state) {
1460 case RPORT_ST_PRLI:
1461 case RPORT_ST_RTV:
1462 case RPORT_ST_READY:
1463 case RPORT_ST_ADISC:
1464 reason = ELS_RJT_NONE;
1465 break;
1466 default:
1467 fc_frame_free(rx_fp);
1468 return;
1469 break;
1470 }
1471 len = fr_len(rx_fp) - sizeof(*fh); 1457 len = fr_len(rx_fp) - sizeof(*fh);
1472 pp = fc_frame_payload_get(rx_fp, sizeof(*pp)); 1458 pp = fc_frame_payload_get(rx_fp, sizeof(*pp));
1473 if (pp == NULL) { 1459 if (!pp)
1474 reason = ELS_RJT_PROT; 1460 goto reject_len;
1475 explan = ELS_EXPL_INV_LEN; 1461 plen = ntohs(pp->prli.prli_len);
1476 } else { 1462 if ((plen % 4) != 0 || plen > len || plen < 16)
1477 plen = ntohs(pp->prli.prli_len); 1463 goto reject_len;
1478 if ((plen % 4) != 0 || plen > len) { 1464 if (plen < len)
1479 reason = ELS_RJT_PROT; 1465 len = plen;
1480 explan = ELS_EXPL_INV_LEN; 1466 plen = pp->prli.prli_spp_len;
1481 } else if (plen < len) { 1467 if ((plen % 4) != 0 || plen < sizeof(*spp) ||
1482 len = plen; 1468 plen > len || len < sizeof(*pp) || plen < 12)
1483 } 1469 goto reject_len;
1484 plen = pp->prli.prli_spp_len; 1470 rspp = &pp->spp;
1485 if ((plen % 4) != 0 || plen < sizeof(*spp) || 1471
1486 plen > len || len < sizeof(*pp)) { 1472 fp = fc_frame_alloc(lport, len);
1487 reason = ELS_RJT_PROT; 1473 if (!fp) {
1488 explan = ELS_EXPL_INV_LEN; 1474 rjt_data.reason = ELS_RJT_UNAB;
1489 } 1475 rjt_data.explan = ELS_EXPL_INSUF_RES;
1490 rspp = &pp->spp; 1476 goto reject;
1491 } 1477 }
1492 if (reason != ELS_RJT_NONE || 1478 sp = lport->tt.seq_start_next(sp);
1493 (fp = fc_frame_alloc(lport, len)) == NULL) { 1479 WARN_ON(!sp);
1494 rjt_data.reason = reason; 1480 pp = fc_frame_payload_get(fp, len);
1495 rjt_data.explan = explan; 1481 WARN_ON(!pp);
1496 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); 1482 memset(pp, 0, len);
1497 } else { 1483 pp->prli.prli_cmd = ELS_LS_ACC;
1498 sp = lport->tt.seq_start_next(sp); 1484 pp->prli.prli_spp_len = plen;
1499 WARN_ON(!sp); 1485 pp->prli.prli_len = htons(len);
1500 pp = fc_frame_payload_get(fp, len); 1486 len -= sizeof(struct fc_els_prli);
1501 WARN_ON(!pp);
1502 memset(pp, 0, len);
1503 pp->prli.prli_cmd = ELS_LS_ACC;
1504 pp->prli.prli_spp_len = plen;
1505 pp->prli.prli_len = htons(len);
1506 len -= sizeof(struct fc_els_prli);
1507
1508 /* reinitialize remote port roles */
1509 rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN;
1510
1511 /*
1512 * Go through all the service parameter pages and build
1513 * response. If plen indicates longer SPP than standard,
1514 * use that. The entire response has been pre-cleared above.
1515 */
1516 spp = &pp->spp;
1517 while (len >= plen) {
1518 spp->spp_type = rspp->spp_type;
1519 spp->spp_type_ext = rspp->spp_type_ext;
1520 spp->spp_flags = rspp->spp_flags & FC_SPP_EST_IMG_PAIR;
1521 resp = FC_SPP_RESP_ACK;
1522 if (rspp->spp_flags & FC_SPP_RPA_VAL)
1523 resp = FC_SPP_RESP_NO_PA;
1524 switch (rspp->spp_type) {
1525 case 0: /* common to all FC-4 types */
1526 break;
1527 case FC_TYPE_FCP:
1528 fcp_parm = ntohl(rspp->spp_params);
1529 if (fcp_parm & FCP_SPPF_RETRY)
1530 rdata->flags |= FC_RP_FLAGS_RETRY;
1531 rdata->supported_classes = FC_COS_CLASS3;
1532 if (fcp_parm & FCP_SPPF_INIT_FCN)
1533 roles |= FC_RPORT_ROLE_FCP_INITIATOR;
1534 if (fcp_parm & FCP_SPPF_TARG_FCN)
1535 roles |= FC_RPORT_ROLE_FCP_TARGET;
1536 rdata->ids.roles = roles;
1537
1538 spp->spp_params =
1539 htonl(lport->service_params);
1540 break;
1541 default:
1542 resp = FC_SPP_RESP_INVL;
1543 break;
1544 }
1545 spp->spp_flags |= resp;
1546 len -= plen;
1547 rspp = (struct fc_els_spp *)((char *)rspp + plen);
1548 spp = (struct fc_els_spp *)((char *)spp + plen);
1549 }
1550 1487
1551 /* 1488 /* reinitialize remote port roles */
1552 * Send LS_ACC. If this fails, the originator should retry. 1489 rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN;
1553 */
1554 f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
1555 f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
1556 ep = fc_seq_exch(sp);
1557 fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
1558 FC_TYPE_ELS, f_ctl, 0);
1559 lport->tt.seq_send(lport, sp, fp);
1560 1490
1561 /* 1491 /*
1562 * Get lock and re-check state. 1492 * Go through all the service parameter pages and build
1563 */ 1493 * response. If plen indicates longer SPP than standard,
1564 switch (rdata->rp_state) { 1494 * use that. The entire response has been pre-cleared above.
1565 case RPORT_ST_PRLI: 1495 */
1566 fc_rport_enter_ready(rdata); 1496 spp = &pp->spp;
1497 while (len >= plen) {
1498 spp->spp_type = rspp->spp_type;
1499 spp->spp_type_ext = rspp->spp_type_ext;
1500 spp->spp_flags = rspp->spp_flags & FC_SPP_EST_IMG_PAIR;
1501 resp = FC_SPP_RESP_ACK;
1502
1503 switch (rspp->spp_type) {
1504 case 0: /* common to all FC-4 types */
1567 break; 1505 break;
1568 case RPORT_ST_READY: 1506 case FC_TYPE_FCP:
1569 case RPORT_ST_ADISC: 1507 fcp_parm = ntohl(rspp->spp_params);
1508 if (fcp_parm & FCP_SPPF_RETRY)
1509 rdata->flags |= FC_RP_FLAGS_RETRY;
1510 rdata->supported_classes = FC_COS_CLASS3;
1511 if (fcp_parm & FCP_SPPF_INIT_FCN)
1512 roles |= FC_RPORT_ROLE_FCP_INITIATOR;
1513 if (fcp_parm & FCP_SPPF_TARG_FCN)
1514 roles |= FC_RPORT_ROLE_FCP_TARGET;
1515 rdata->ids.roles = roles;
1516
1517 spp->spp_params = htonl(lport->service_params);
1570 break; 1518 break;
1571 default: 1519 default:
1520 resp = FC_SPP_RESP_INVL;
1572 break; 1521 break;
1573 } 1522 }
1523 spp->spp_flags |= resp;
1524 len -= plen;
1525 rspp = (struct fc_els_spp *)((char *)rspp + plen);
1526 spp = (struct fc_els_spp *)((char *)spp + plen);
1527 }
1528
1529 /*
1530 * Send LS_ACC. If this fails, the originator should retry.
1531 */
1532 f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
1533 f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
1534 ep = fc_seq_exch(sp);
1535 fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
1536 FC_TYPE_ELS, f_ctl, 0);
1537 lport->tt.seq_send(lport, sp, fp);
1538
1539 switch (rdata->rp_state) {
1540 case RPORT_ST_PRLI:
1541 fc_rport_enter_ready(rdata);
1542 break;
1543 default:
1544 break;
1574 } 1545 }
1546 goto drop;
1547
1548reject_len:
1549 rjt_data.reason = ELS_RJT_PROT;
1550 rjt_data.explan = ELS_EXPL_INV_LEN;
1551reject:
1552 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1553drop:
1575 fc_frame_free(rx_fp); 1554 fc_frame_free(rx_fp);
1576} 1555}
1577 1556