[SCSI] qla2xxx: Add iIDMA support.
iIDMA (Intelligent Interleaved Direct Memory Access) allows for
the HBA hardware to send FC frames at the rate at which they can
be received by a target device. By taking advantage of the
higher link rate, the HBA can maximize bandwidth utilization in a
heterogeneous multi-speed SAN.
Within a fabric topology, port speed detection is done via a Name
Server command (GFPN_ID) followed by a Fabric Management command
(GPSC). In an FCAL/N2N topology, port speed is based on the HBA
link-rate.
Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 8596491..2700964 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -2074,6 +2074,19 @@
new_fcport->flags &= ~FCF_FABRIC_DEVICE;
}
+ /* Base iIDMA settings on HBA port speed. */
+ switch (ha->link_data_rate) {
+ case PORT_SPEED_1GB:
+ fcport->fp_speed = cpu_to_be16(BIT_15);
+ break;
+ case PORT_SPEED_2GB:
+ fcport->fp_speed = cpu_to_be16(BIT_14);
+ break;
+ case PORT_SPEED_4GB:
+ fcport->fp_speed = cpu_to_be16(BIT_13);
+ break;
+ }
+
qla2x00_update_fcport(ha, fcport);
found_devs++;
@@ -2109,6 +2122,62 @@
}
}
+static void
+qla2x00_iidma_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
+{
+#define LS_UNKNOWN 2
+ static char *link_speeds[5] = { "1", "2", "?", "4" };
+ int rval;
+ uint16_t port_speed, mb[6];
+
+ if (!IS_QLA24XX(ha))
+ return;
+
+ switch (be16_to_cpu(fcport->fp_speed)) {
+ case BIT_15:
+ port_speed = PORT_SPEED_1GB;
+ break;
+ case BIT_14:
+ port_speed = PORT_SPEED_2GB;
+ break;
+ case BIT_13:
+ port_speed = PORT_SPEED_4GB;
+ break;
+ default:
+ DEBUG2(printk("scsi(%ld): %02x%02x%02x%02x%02x%02x%02x%02x -- "
+ "unsupported FM port operating speed (%04x).\n",
+ ha->host_no, fcport->port_name[0], fcport->port_name[1],
+ fcport->port_name[2], fcport->port_name[3],
+ fcport->port_name[4], fcport->port_name[5],
+ fcport->port_name[6], fcport->port_name[7],
+ be16_to_cpu(fcport->fp_speed)));
+ port_speed = PORT_SPEED_UNKNOWN;
+ break;
+ }
+ if (port_speed == PORT_SPEED_UNKNOWN)
+ return;
+
+ rval = qla2x00_set_idma_speed(ha, fcport->loop_id, port_speed, mb);
+ if (rval != QLA_SUCCESS) {
+ DEBUG2(printk("scsi(%ld): Unable to adjust iIDMA "
+ "%02x%02x%02x%02x%02x%02x%02x%02x -- %04x %x %04x %04x.\n",
+ ha->host_no, fcport->port_name[0], fcport->port_name[1],
+ fcport->port_name[2], fcport->port_name[3],
+ fcport->port_name[4], fcport->port_name[5],
+ fcport->port_name[6], fcport->port_name[7], rval,
+ port_speed, mb[0], mb[1]));
+ } else {
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "iIDMA adjusted to %s GB/s on "
+ "%02x%02x%02x%02x%02x%02x%02x%02x.\n",
+ link_speeds[port_speed], fcport->port_name[0],
+ fcport->port_name[1], fcport->port_name[2],
+ fcport->port_name[3], fcport->port_name[4],
+ fcport->port_name[5], fcport->port_name[6],
+ fcport->port_name[7]));
+ }
+}
+
/*
* qla2x00_update_fcport
* Updates device on list.
@@ -2135,6 +2204,8 @@
PORT_RETRY_TIME);
fcport->flags &= ~FCF_LOGIN_NEEDED;
+ qla2x00_iidma_fcport(ha, fcport);
+
atomic_set(&fcport->state, FCS_ONLINE);
if (ha->flags.init_done)
@@ -2416,6 +2487,8 @@
} else if (qla2x00_gnn_id(ha, swl) != QLA_SUCCESS) {
kfree(swl);
swl = NULL;
+ } else if (qla2x00_gfpn_id(ha, swl) == QLA_SUCCESS) {
+ qla2x00_gpsc(ha, swl);
}
}
swl_idx = 0;
@@ -2450,6 +2523,9 @@
swl[swl_idx].node_name, WWN_SIZE);
memcpy(new_fcport->port_name,
swl[swl_idx].port_name, WWN_SIZE);
+ memcpy(new_fcport->fabric_port_name,
+ swl[swl_idx].fabric_port_name, WWN_SIZE);
+ new_fcport->fp_speed = swl[swl_idx].fp_speed;
if (swl[swl_idx].d_id.b.rsvd_1 != 0) {
last_dev = 1;
@@ -2507,6 +2583,11 @@
found++;
+ /* Update port state. */
+ memcpy(fcport->fabric_port_name,
+ new_fcport->fabric_port_name, WWN_SIZE);
+ fcport->fp_speed = new_fcport->fp_speed;
+
/*
* If address the same and state FCS_ONLINE, nothing
* changed.