Merge master.kernel.org:/pub/scm/linux/kernel/git/davej/agpgart
[pandora-kernel.git] / drivers / scsi / qla2xxx / qla_gs.c
index cd6f7c3..ec5b2dd 100644 (file)
@@ -126,9 +126,9 @@ qla2x00_chk_ms_status(scsi_qla_host_t *ha, ms_iocb_entry_t *ms_pkt,
                DEBUG2_3(printk("scsi(%ld): %s failed, error status (%x).\n",
                    ha->host_no, routine, ms_pkt->entry_status));
        } else {
-               if (IS_QLA24XX(ha) || IS_QLA25XX(ha))
-                       comp_status =
-                           ((struct ct_entry_24xx *)ms_pkt)->comp_status;
+               if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+                       comp_status = le16_to_cpu(
+                           ((struct ct_entry_24xx *)ms_pkt)->comp_status);
                else
                        comp_status = le16_to_cpu(ms_pkt->status);
                switch (comp_status) {
@@ -143,6 +143,7 @@ qla2x00_chk_ms_status(scsi_qla_host_t *ha, ms_iocb_entry_t *ms_pkt,
                                DEBUG2_3(qla2x00_dump_buffer(
                                    (uint8_t *)&ct_rsp->header,
                                    sizeof(struct ct_rsp_hdr)));
+                               rval = QLA_INVALID_COMMAND;
                        } else
                                rval = QLA_SUCCESS;
                        break;
@@ -538,6 +539,7 @@ qla2x00_rff_id(scsi_qla_host_t *ha)
        ct_req->req.rff_id.port_id[1] = ha->d_id.b.area;
        ct_req->req.rff_id.port_id[2] = ha->d_id.b.al_pa;
 
+       ct_req->req.rff_id.fc4_feature = BIT_1;
        ct_req->req.rff_id.fc4_type = 0x08;             /* SCSI - FCP */
 
        /* Execute MS IOCB */
@@ -611,6 +613,14 @@ qla2x00_rnn_id(scsi_qla_host_t *ha)
        return (rval);
 }
 
+void
+qla2x00_get_sym_node_name(scsi_qla_host_t *ha, uint8_t *snn)
+{
+       sprintf(snn, "%s FW:v%d.%02d.%02d DVR:v%s",ha->model_number,
+           ha->fw_major_version, ha->fw_minor_version,
+           ha->fw_subminor_version, qla2x00_version_str);
+}
+
 /**
  * qla2x00_rsnn_nn() - SNS Register Symbolic Node Name (RSNN_NN) of the HBA.
  * @ha: HA context
@@ -621,9 +631,6 @@ int
 qla2x00_rsnn_nn(scsi_qla_host_t *ha)
 {
        int             rval;
-       uint8_t         *snn;
-       uint8_t         version[20];
-
        ms_iocb_entry_t *ms_pkt;
        struct ct_sns_req       *ct_req;
        struct ct_sns_rsp       *ct_rsp;
@@ -648,20 +655,11 @@ qla2x00_rsnn_nn(scsi_qla_host_t *ha)
        memcpy(ct_req->req.rsnn_nn.node_name, ha->node_name, WWN_SIZE);
 
        /* Prepare the Symbolic Node Name */
-       /* Board type */
-       snn = ct_req->req.rsnn_nn.sym_node_name;
-       strcpy(snn, ha->model_number);
-       /* Firmware version */
-       strcat(snn, " FW:v");
-       sprintf(version, "%d.%02d.%02d", ha->fw_major_version,
-           ha->fw_minor_version, ha->fw_subminor_version);
-       strcat(snn, version);
-       /* Driver version */
-       strcat(snn, " DVR:v");
-       strcat(snn, qla2x00_version_str);
+       qla2x00_get_sym_node_name(ha, ct_req->req.rsnn_nn.sym_node_name);
 
        /* Calculate SNN length */
-       ct_req->req.rsnn_nn.name_len = (uint8_t)strlen(snn);
+       ct_req->req.rsnn_nn.name_len =
+           (uint8_t)strlen(ct_req->req.rsnn_nn.sym_node_name);
 
        /* Update MS IOCB request */
        ms_pkt->req_bytecount =
@@ -686,7 +684,6 @@ qla2x00_rsnn_nn(scsi_qla_host_t *ha)
        return (rval);
 }
 
-
 /**
  * qla2x00_prep_sns_cmd() - Prepare common SNS command request fields for query.
  * @ha: HA context
@@ -1199,7 +1196,7 @@ qla2x00_update_ms_fdmi_iocb(scsi_qla_host_t *ha, uint32_t req_size)
        ms_iocb_entry_t *ms_pkt = ha->ms_iocb;
        struct ct_entry_24xx *ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb;
 
-       if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) {
+       if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
                ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
                ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count;
        } else {
@@ -1528,10 +1525,8 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
        eiter = (struct ct_fdmi_port_attr *) (entries + size);
        eiter->type = __constant_cpu_to_be16(FDMI_PORT_SUPPORT_SPEED);
        eiter->len = __constant_cpu_to_be16(4 + 4);
-       if (IS_QLA25XX(ha))
+       if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
                eiter->a.sup_speed = __constant_cpu_to_be32(4);
-       else if (IS_QLA24XX(ha))
-               eiter->a.sup_speed = __constant_cpu_to_be32(8);
        else if (IS_QLA23XX(ha))
                eiter->a.sup_speed = __constant_cpu_to_be32(2);
        else
@@ -1553,9 +1548,6 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
                eiter->a.cur_speed = __constant_cpu_to_be32(2);
                break;
        case 3:
-               eiter->a.cur_speed = __constant_cpu_to_be32(8);
-               break;
-       case 4:
                eiter->a.cur_speed = __constant_cpu_to_be32(4);
                break;
        }
@@ -1568,7 +1560,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
        eiter = (struct ct_fdmi_port_attr *) (entries + size);
        eiter->type = __constant_cpu_to_be16(FDMI_PORT_MAX_FRAME_SIZE);
        eiter->len = __constant_cpu_to_be16(4 + 4);
-       max_frame_size = IS_QLA24XX(ha) || IS_QLA25XX(ha) ?
+       max_frame_size = IS_QLA24XX(ha) || IS_QLA54XX(ha) ?
                (uint32_t) icb24->frame_payload_size:
                (uint32_t) ha->init_cb->frame_payload_size;
        eiter->a.max_frame_size = cpu_to_be32(max_frame_size);
@@ -1589,6 +1581,21 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
        DEBUG13(printk("%s(%ld): OS_DEVICE_NAME=%s.\n", __func__, ha->host_no,
            eiter->a.os_dev_name));
 
+       /* Hostname. */
+       if (strlen(fc_host_system_hostname(ha->host))) {
+               eiter = (struct ct_fdmi_port_attr *) (entries + size);
+               eiter->type = __constant_cpu_to_be16(FDMI_PORT_HOST_NAME);
+               snprintf(eiter->a.host_name, sizeof(eiter->a.host_name),
+                   "%s", fc_host_system_hostname(ha->host));
+               alen = strlen(eiter->a.host_name);
+               alen += (alen & 3) ? (4 - (alen & 3)) : 4;
+               eiter->len = cpu_to_be16(4 + alen);
+               size += 4 + alen;
+
+               DEBUG13(printk("%s(%ld): HOSTNAME=%s.\n", __func__,
+                   ha->host_no, eiter->a.host_name));
+       }
+
        /* Update MS request size. */
        qla2x00_update_ms_fdmi_iocb(ha, size + 16);
 
@@ -1651,3 +1658,202 @@ qla2x00_fdmi_register(scsi_qla_host_t *ha)
 
        return rval;
 }
+
+/**
+ * qla2x00_gfpn_id() - SNS Get Fabric Port Name (GFPN_ID) query.
+ * @ha: HA context
+ * @list: switch info entries to populate
+ *
+ * Returns 0 on success.
+ */
+int
+qla2x00_gfpn_id(scsi_qla_host_t *ha, sw_info_t *list)
+{
+       int             rval;
+       uint16_t        i;
+
+       ms_iocb_entry_t *ms_pkt;
+       struct ct_sns_req       *ct_req;
+       struct ct_sns_rsp       *ct_rsp;
+
+       if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+               return QLA_FUNCTION_FAILED;
+
+       for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
+               /* Issue GFPN_ID */
+               memset(list[i].fabric_port_name, 0, WWN_SIZE);
+
+               /* Prepare common MS IOCB */
+               ms_pkt = ha->isp_ops.prep_ms_iocb(ha, GFPN_ID_REQ_SIZE,
+                   GFPN_ID_RSP_SIZE);
+
+               /* Prepare CT request */
+               ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GFPN_ID_CMD,
+                   GFPN_ID_RSP_SIZE);
+               ct_rsp = &ha->ct_sns->p.rsp;
+
+               /* Prepare CT arguments -- port_id */
+               ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain;
+               ct_req->req.port_id.port_id[1] = list[i].d_id.b.area;
+               ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa;
+
+               /* Execute MS IOCB */
+               rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma,
+                   sizeof(ms_iocb_entry_t));
+               if (rval != QLA_SUCCESS) {
+                       /*EMPTY*/
+                       DEBUG2_3(printk("scsi(%ld): GFPN_ID issue IOCB "
+                           "failed (%d).\n", ha->host_no, rval));
+               } else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp,
+                   "GFPN_ID") != QLA_SUCCESS) {
+                       rval = QLA_FUNCTION_FAILED;
+               } else {
+                       /* Save fabric portname */
+                       memcpy(list[i].fabric_port_name,
+                           ct_rsp->rsp.gfpn_id.port_name, WWN_SIZE);
+               }
+
+               /* Last device exit. */
+               if (list[i].d_id.b.rsvd_1 != 0)
+                       break;
+       }
+
+       return (rval);
+}
+
+static inline void *
+qla24xx_prep_ms_fm_iocb(scsi_qla_host_t *ha, uint32_t req_size,
+    uint32_t rsp_size)
+{
+       struct ct_entry_24xx *ct_pkt;
+
+       ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb;
+       memset(ct_pkt, 0, sizeof(struct ct_entry_24xx));
+
+       ct_pkt->entry_type = CT_IOCB_TYPE;
+       ct_pkt->entry_count = 1;
+       ct_pkt->nport_handle = cpu_to_le16(ha->mgmt_svr_loop_id);
+       ct_pkt->timeout = __constant_cpu_to_le16(59);
+       ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1);
+       ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1);
+       ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size);
+       ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
+
+       ct_pkt->dseg_0_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
+       ct_pkt->dseg_0_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
+       ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count;
+
+       ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
+       ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
+       ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count;
+
+       return ct_pkt;
+}
+
+
+static inline struct ct_sns_req *
+qla24xx_prep_ct_fm_req(struct ct_sns_req *ct_req, uint16_t cmd,
+    uint16_t rsp_size)
+{
+       memset(ct_req, 0, sizeof(struct ct_sns_pkt));
+
+       ct_req->header.revision = 0x01;
+       ct_req->header.gs_type = 0xFA;
+       ct_req->header.gs_subtype = 0x01;
+       ct_req->command = cpu_to_be16(cmd);
+       ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4);
+
+       return ct_req;
+}
+
+/**
+ * qla2x00_gpsc() - FCS Get Port Speed Capabilities (GPSC) query.
+ * @ha: HA context
+ * @list: switch info entries to populate
+ *
+ * Returns 0 on success.
+ */
+int
+qla2x00_gpsc(scsi_qla_host_t *ha, sw_info_t *list)
+{
+       int             rval;
+       uint16_t        i;
+
+       ms_iocb_entry_t *ms_pkt;
+       struct ct_sns_req       *ct_req;
+       struct ct_sns_rsp       *ct_rsp;
+
+       if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+               return QLA_FUNCTION_FAILED;
+       if (!ha->flags.gpsc_supported)
+               return QLA_FUNCTION_FAILED;
+
+       rval = qla2x00_mgmt_svr_login(ha);
+       if (rval)
+               return rval;
+
+       for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
+               /* Issue GFPN_ID */
+               list[i].fp_speeds = list[i].fp_speed = 0;
+
+               /* Prepare common MS IOCB */
+               ms_pkt = qla24xx_prep_ms_fm_iocb(ha, GPSC_REQ_SIZE,
+                   GPSC_RSP_SIZE);
+
+               /* Prepare CT request */
+               ct_req = qla24xx_prep_ct_fm_req(&ha->ct_sns->p.req,
+                   GPSC_CMD, GPSC_RSP_SIZE);
+               ct_rsp = &ha->ct_sns->p.rsp;
+
+               /* Prepare CT arguments -- port_name */
+               memcpy(ct_req->req.gpsc.port_name, list[i].fabric_port_name,
+                   WWN_SIZE);
+
+               /* Execute MS IOCB */
+               rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma,
+                   sizeof(ms_iocb_entry_t));
+               if (rval != QLA_SUCCESS) {
+                       /*EMPTY*/
+                       DEBUG2_3(printk("scsi(%ld): GPSC issue IOCB "
+                           "failed (%d).\n", ha->host_no, rval));
+               } else if ((rval = qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp,
+                   "GPSC")) != QLA_SUCCESS) {
+                       /* FM command unsupported? */
+                       if (rval == QLA_INVALID_COMMAND &&
+                           ct_rsp->header.reason_code ==
+                           CT_REASON_INVALID_COMMAND_CODE) {
+                               DEBUG2(printk("scsi(%ld): GPSC command "
+                                   "unsupported, disabling query...\n",
+                                   ha->host_no));
+                               ha->flags.gpsc_supported = 0;
+                               rval = QLA_FUNCTION_FAILED;
+                               break;
+                       }
+                       rval = QLA_FUNCTION_FAILED;
+               } else {
+                       /* Save portname */
+                       list[i].fp_speeds = ct_rsp->rsp.gpsc.speeds;
+                       list[i].fp_speed = ct_rsp->rsp.gpsc.speed;
+
+                       DEBUG2_3(printk("scsi(%ld): GPSC ext entry - "
+                           "fpn %02x%02x%02x%02x%02x%02x%02x%02x speeds=%04x "
+                           "speed=%04x.\n", ha->host_no,
+                           list[i].fabric_port_name[0],
+                           list[i].fabric_port_name[1],
+                           list[i].fabric_port_name[2],
+                           list[i].fabric_port_name[3],
+                           list[i].fabric_port_name[4],
+                           list[i].fabric_port_name[5],
+                           list[i].fabric_port_name[6],
+                           list[i].fabric_port_name[7],
+                           be16_to_cpu(list[i].fp_speeds),
+                           be16_to_cpu(list[i].fp_speed)));
+               }
+
+               /* Last device exit. */
+               if (list[i].d_id.b.rsvd_1 != 0)
+                       break;
+       }
+
+       return (rval);
+}