aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/lpfc/lpfc_nportdisc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_nportdisc.c')
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c69
1 files changed, 45 insertions, 24 deletions
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index 507a6af56f42..fbead786031f 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -55,55 +55,76 @@ lpfc_check_adisc(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
return (1);
}
-
int
lpfc_check_sparm(struct lpfc_hba * phba,
struct lpfc_nodelist * ndlp, struct serv_parm * sp,
uint32_t class)
{
volatile struct serv_parm *hsp = &phba->fc_sparam;
- /* First check for supported version */
-
- /* Next check for class validity */
+ uint16_t hsp_value, ssp_value = 0;
+
+ /*
+ * The receive data field size and buffer-to-buffer receive data field
+ * size entries are 16 bits but are represented as two 8-bit fields in
+ * the driver data structure to account for rsvd bits and other control
+ * bits. Reconstruct and compare the fields as a 16-bit values before
+ * correcting the byte values.
+ */
if (sp->cls1.classValid) {
-
- if (sp->cls1.rcvDataSizeMsb > hsp->cls1.rcvDataSizeMsb)
- sp->cls1.rcvDataSizeMsb = hsp->cls1.rcvDataSizeMsb;
- if (sp->cls1.rcvDataSizeLsb > hsp->cls1.rcvDataSizeLsb)
+ hsp_value = (hsp->cls1.rcvDataSizeMsb << 8) |
+ hsp->cls1.rcvDataSizeLsb;
+ ssp_value = (sp->cls1.rcvDataSizeMsb << 8) |
+ sp->cls1.rcvDataSizeLsb;
+ if (ssp_value > hsp_value) {
sp->cls1.rcvDataSizeLsb = hsp->cls1.rcvDataSizeLsb;
+ sp->cls1.rcvDataSizeMsb = hsp->cls1.rcvDataSizeMsb;
+ }
} else if (class == CLASS1) {
- return (0);
+ return 0;
}
if (sp->cls2.classValid) {
-
- if (sp->cls2.rcvDataSizeMsb > hsp->cls2.rcvDataSizeMsb)
- sp->cls2.rcvDataSizeMsb = hsp->cls2.rcvDataSizeMsb;
- if (sp->cls2.rcvDataSizeLsb > hsp->cls2.rcvDataSizeLsb)
+ hsp_value = (hsp->cls2.rcvDataSizeMsb << 8) |
+ hsp->cls2.rcvDataSizeLsb;
+ ssp_value = (sp->cls2.rcvDataSizeMsb << 8) |
+ sp->cls2.rcvDataSizeLsb;
+ if (ssp_value > hsp_value) {
sp->cls2.rcvDataSizeLsb = hsp->cls2.rcvDataSizeLsb;
+ sp->cls2.rcvDataSizeMsb = hsp->cls2.rcvDataSizeMsb;
+ }
} else if (class == CLASS2) {
- return (0);
+ return 0;
}
if (sp->cls3.classValid) {
-
- if (sp->cls3.rcvDataSizeMsb > hsp->cls3.rcvDataSizeMsb)
- sp->cls3.rcvDataSizeMsb = hsp->cls3.rcvDataSizeMsb;
- if (sp->cls3.rcvDataSizeLsb > hsp->cls3.rcvDataSizeLsb)
+ hsp_value = (hsp->cls3.rcvDataSizeMsb << 8) |
+ hsp->cls3.rcvDataSizeLsb;
+ ssp_value = (sp->cls3.rcvDataSizeMsb << 8) |
+ sp->cls3.rcvDataSizeLsb;
+ if (ssp_value > hsp_value) {
sp->cls3.rcvDataSizeLsb = hsp->cls3.rcvDataSizeLsb;
+ sp->cls3.rcvDataSizeMsb = hsp->cls3.rcvDataSizeMsb;
+ }
} else if (class == CLASS3) {
- return (0);
+ return 0;
}
- if (sp->cmn.bbRcvSizeMsb > hsp->cmn.bbRcvSizeMsb)
- sp->cmn.bbRcvSizeMsb = hsp->cmn.bbRcvSizeMsb;
- if (sp->cmn.bbRcvSizeLsb > hsp->cmn.bbRcvSizeLsb)
+ /*
+ * Preserve the upper four bits of the MSB from the PLOGI response.
+ * These bits contain the Buffer-to-Buffer State Change Number
+ * from the target and need to be passed to the FW.
+ */
+ hsp_value = (hsp->cmn.bbRcvSizeMsb << 8) | hsp->cmn.bbRcvSizeLsb;
+ ssp_value = (sp->cmn.bbRcvSizeMsb << 8) | sp->cmn.bbRcvSizeLsb;
+ if (ssp_value > hsp_value) {
sp->cmn.bbRcvSizeLsb = hsp->cmn.bbRcvSizeLsb;
+ sp->cmn.bbRcvSizeMsb = (sp->cmn.bbRcvSizeMsb & 0xF0) |
+ (hsp->cmn.bbRcvSizeMsb & 0x0F);
+ }
- /* If check is good, copy wwpn wwnn into ndlp */
memcpy(&ndlp->nlp_nodename, &sp->nodeName, sizeof (struct lpfc_name));
memcpy(&ndlp->nlp_portname, &sp->portName, sizeof (struct lpfc_name));
- return (1);
+ return 1;
}
static void *