diff options
author | Joe Eykholt <jeykholt@cisco.com> | 2010-03-12 19:07:36 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-04-11 10:23:33 -0400 |
commit | a2f6a024e1a7ce37f424a567733501d98b8555d7 (patch) | |
tree | df6fd29c5b7b8459077c09be3dac6829b22ae58a /drivers/scsi/libfc | |
parent | fc193172e63af2c749e198816a1ee694dd6395e6 (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')
-rw-r--r-- | drivers/scsi/libfc/fc_rport.c | 195 |
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 | |||
1548 | reject_len: | ||
1549 | rjt_data.reason = ELS_RJT_PROT; | ||
1550 | rjt_data.explan = ELS_EXPL_INV_LEN; | ||
1551 | reject: | ||
1552 | lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); | ||
1553 | drop: | ||
1575 | fc_frame_free(rx_fp); | 1554 | fc_frame_free(rx_fp); |
1576 | } | 1555 | } |
1577 | 1556 | ||