Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
[linux-2.6.git] / drivers / scsi / qla4xxx / ql4_mbx.c
index 72ec7e0..c259378 100644 (file)
@@ -41,6 +41,16 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
                return status;
        }
 
+       if (is_qla40XX(ha)) {
+               if (test_bit(AF_HA_REMOVAL, &ha->flags)) {
+                       DEBUG2(ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: "
+                                         "prematurely completing mbx cmd as "
+                                         "adapter removal detected\n",
+                                         ha->host_no, __func__));
+                       return status;
+               }
+       }
+
        if (is_qla8022(ha)) {
                if (test_bit(AF_FW_RECOVERY, &ha->flags)) {
                        DEBUG2(ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: "
@@ -333,6 +343,9 @@ qla4xxx_update_local_ip(struct scsi_qla_host *ha,
        ha->ip_config.ipv4_options = le16_to_cpu(init_fw_cb->ipv4_ip_opts);
        ha->ip_config.ipv4_addr_state =
                                le16_to_cpu(init_fw_cb->ipv4_addr_state);
+       ha->ip_config.eth_mtu_size =
+                               le16_to_cpu(init_fw_cb->eth_mtu_size);
+       ha->ip_config.ipv4_port = le16_to_cpu(init_fw_cb->ipv4_port);
 
        if (ha->acb_version == ACB_SUPPORTED) {
                ha->ip_config.ipv6_options = le16_to_cpu(init_fw_cb->ipv6_opts);
@@ -382,6 +395,7 @@ qla4xxx_update_local_ip(struct scsi_qla_host *ha,
                           sizeof(init_fw_cb->ipv6_dflt_rtr_addr)));
                ha->ip_config.ipv6_vlan_tag =
                                be16_to_cpu(init_fw_cb->ipv6_vlan_tag);
+               ha->ip_config.ipv6_port = le16_to_cpu(init_fw_cb->ipv6_port);
        }
 }
 
@@ -409,6 +423,7 @@ qla4xxx_update_local_ifcb(struct scsi_qla_host *ha,
        memcpy(ha->name_string, init_fw_cb->iscsi_name,
                min(sizeof(ha->name_string),
                sizeof(init_fw_cb->iscsi_name)));
+       ha->def_timeout = le16_to_cpu(init_fw_cb->def_timeout);
        /*memcpy(ha->alias, init_fw_cb->Alias,
               min(sizeof(ha->alias), sizeof(init_fw_cb->Alias)));*/
 
@@ -868,7 +883,6 @@ void qla4xxx_get_conn_event_log(struct scsi_qla_host * ha)
        uint32_t        max_event_log_entries;
        uint8_t         i;
 
-
        memset(&mbox_cmd, 0, sizeof(mbox_cmd));
        memset(&mbox_sts, 0, sizeof(mbox_cmd));
 
@@ -1301,7 +1315,7 @@ int qla4xxx_get_chap(struct scsi_qla_host *ha, char *username, char *password,
 {
        int ret = 0;
        int rval = QLA_ERROR;
-       uint32_t offset = 0;
+       uint32_t offset = 0, chap_size;
        struct ql4_chap_table *chap_table;
        dma_addr_t chap_dma;
 
@@ -1311,12 +1325,22 @@ int qla4xxx_get_chap(struct scsi_qla_host *ha, char *username, char *password,
                goto exit_get_chap;
        }
 
-       memset(chap_table, 0, sizeof(struct ql4_chap_table));
-
-       offset = 0x06000000 | (idx * sizeof(struct ql4_chap_table));
+       chap_size = sizeof(struct ql4_chap_table);
+       memset(chap_table, 0, chap_size);
+
+       if (is_qla40XX(ha))
+               offset = FLASH_CHAP_OFFSET | (idx * chap_size);
+       else {
+               offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_chap << 2);
+               /* flt_chap_size is CHAP table size for both ports
+                * so divide it by 2 to calculate the offset for second port
+                */
+               if (ha->port_num == 1)
+                       offset += (ha->hw.flt_chap_size / 2);
+               offset += (idx * chap_size);
+       }
 
-       rval = qla4xxx_get_flash(ha, chap_dma, offset,
-                                sizeof(struct ql4_chap_table));
+       rval = qla4xxx_get_flash(ha, chap_dma, offset, chap_size);
        if (rval != QLA_SUCCESS) {
                ret = -EINVAL;
                goto exit_get_chap;
@@ -1363,10 +1387,16 @@ static int qla4xxx_set_chap(struct scsi_qla_host *ha, char *username,
        strncpy(chap_table->secret, password, MAX_CHAP_SECRET_LEN);
        strncpy(chap_table->name, username, MAX_CHAP_NAME_LEN);
        chap_table->cookie = __constant_cpu_to_le16(CHAP_VALID_COOKIE);
-       offset = 0x06000000 | (idx * sizeof(struct ql4_chap_table));
+       offset = FLASH_CHAP_OFFSET | (idx * sizeof(struct ql4_chap_table));
        rval = qla4xxx_set_flash(ha, chap_dma, offset,
                                sizeof(struct ql4_chap_table),
                                FLASH_OPT_RMW_COMMIT);
+
+       if (rval == QLA_SUCCESS && ha->chap_list) {
+               /* Update ha chap_list cache */
+               memcpy((struct ql4_chap_table *)ha->chap_list + idx,
+                      chap_table, sizeof(struct ql4_chap_table));
+       }
        dma_pool_free(ha->chap_dma_pool, chap_table, chap_dma);
        if (rval != QLA_SUCCESS)
                ret =  -EINVAL;
@@ -1375,6 +1405,83 @@ exit_set_chap:
        return ret;
 }
 
+/**
+ * qla4xxx_get_chap_index - Get chap index given username and secret
+ * @ha: pointer to adapter structure
+ * @username: CHAP username to be searched
+ * @password: CHAP password to be searched
+ * @bidi: Is this a BIDI CHAP
+ * @chap_index: CHAP index to be returned
+ *
+ * Match the username and password in the chap_list, return the index if a
+ * match is found. If a match is not found then add the entry in FLASH and
+ * return the index at which entry is written in the FLASH.
+ **/
+static int qla4xxx_get_chap_index(struct scsi_qla_host *ha, char *username,
+                           char *password, int bidi, uint16_t *chap_index)
+{
+       int i, rval;
+       int free_index = -1;
+       int found_index = 0;
+       int max_chap_entries = 0;
+       struct ql4_chap_table *chap_table;
+
+       if (is_qla8022(ha))
+               max_chap_entries = (ha->hw.flt_chap_size / 2) /
+                                               sizeof(struct ql4_chap_table);
+       else
+               max_chap_entries = MAX_CHAP_ENTRIES_40XX;
+
+       if (!ha->chap_list) {
+               ql4_printk(KERN_ERR, ha, "Do not have CHAP table cache\n");
+               return QLA_ERROR;
+       }
+
+       mutex_lock(&ha->chap_sem);
+       for (i = 0; i < max_chap_entries; i++) {
+               chap_table = (struct ql4_chap_table *)ha->chap_list + i;
+               if (chap_table->cookie !=
+                   __constant_cpu_to_le16(CHAP_VALID_COOKIE)) {
+                       if (i > MAX_RESRV_CHAP_IDX && free_index == -1)
+                               free_index = i;
+                       continue;
+               }
+               if (bidi) {
+                       if (chap_table->flags & BIT_7)
+                               continue;
+               } else {
+                       if (chap_table->flags & BIT_6)
+                               continue;
+               }
+               if (!strncmp(chap_table->secret, password,
+                            MAX_CHAP_SECRET_LEN) &&
+                   !strncmp(chap_table->name, username,
+                            MAX_CHAP_NAME_LEN)) {
+                       *chap_index = i;
+                       found_index = 1;
+                       break;
+               }
+       }
+
+       /* If chap entry is not present and a free index is available then
+        * write the entry in flash
+        */
+       if (!found_index && free_index != -1) {
+               rval = qla4xxx_set_chap(ha, username, password,
+                                       free_index, bidi);
+               if (!rval) {
+                       *chap_index = free_index;
+                       found_index = 1;
+               }
+       }
+
+       mutex_unlock(&ha->chap_sem);
+
+       if (found_index)
+               return QLA_SUCCESS;
+       return QLA_ERROR;
+}
+
 int qla4xxx_conn_close_sess_logout(struct scsi_qla_host *ha,
                                   uint16_t fw_ddb_index,
                                   uint16_t connection_id,
@@ -1421,18 +1528,21 @@ int qla4xxx_disable_acb(struct scsi_qla_host *ha)
        return status;
 }
 
-int qla4xxx_get_acb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
-                   uint32_t *mbox_sts, dma_addr_t acb_dma)
+int qla4xxx_get_acb(struct scsi_qla_host *ha, dma_addr_t acb_dma,
+                   uint32_t acb_type, uint32_t len)
 {
+       uint32_t mbox_cmd[MBOX_REG_COUNT];
+       uint32_t mbox_sts[MBOX_REG_COUNT];
        int status = QLA_SUCCESS;
 
-       memset(mbox_cmd, 0, sizeof(mbox_cmd[0]) * MBOX_REG_COUNT);
-       memset(mbox_sts, 0, sizeof(mbox_sts[0]) * MBOX_REG_COUNT);
+       memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+       memset(&mbox_sts, 0, sizeof(mbox_sts));
+
        mbox_cmd[0] = MBOX_CMD_GET_ACB;
-       mbox_cmd[1] = 0; /* Primary ACB */
+       mbox_cmd[1] = acb_type;
        mbox_cmd[2] = LSDW(acb_dma);
        mbox_cmd[3] = MSDW(acb_dma);
-       mbox_cmd[4] = sizeof(struct addr_ctrl_blk);
+       mbox_cmd[4] = len;
 
        status = qla4xxx_mailbox_command(ha, 5, 5, &mbox_cmd[0], &mbox_sts[0]);
        if (status != QLA_SUCCESS) {
@@ -1484,7 +1594,6 @@ int qla4xxx_set_param_ddbentry(struct scsi_qla_host *ha,
        uint16_t iscsi_opts = 0;
        uint32_t options = 0;
        uint16_t idx;
-       int max_chap_entries = 0;
 
        fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
                                          &fw_ddb_entry_dma, GFP_KERNEL);
@@ -1553,25 +1662,14 @@ int qla4xxx_set_param_ddbentry(struct scsi_qla_host *ha,
                goto exit_set_param;
        }
 
-       if (is_qla8022(ha))
-               max_chap_entries = MAX_CHAP_ENTRIES_82XX;
-       else
-               max_chap_entries = MAX_CHAP_ENTRIES_40XX;
        /* CHAP */
        if (sess->username != NULL && sess->password != NULL) {
                if (strlen(sess->username) && strlen(sess->password)) {
                        iscsi_opts |= BIT_7;
-                       idx = ddb_entry->fw_ddb_index * 2;
-                       if (idx > max_chap_entries) {
-                               ql4_printk(KERN_ERR, ha,
-                                          "%s: Invalid ddb or chap index\n",
-                                          __func__);
-                               rval  = -EINVAL;
-                               goto exit_set_param;
-                       }
 
-                       rval = qla4xxx_set_chap(ha, sess->username,
-                                               sess->password, idx, 0);
+                       rval = qla4xxx_get_chap_index(ha, sess->username,
+                                               sess->password,
+                                               LOCAL_CHAP, &idx);
                        if (rval)
                                goto exit_set_param;
 
@@ -1583,16 +1681,10 @@ int qla4xxx_set_param_ddbentry(struct scsi_qla_host *ha,
                /* Check if BIDI CHAP */
                if (strlen(sess->username_in) && strlen(sess->password_in)) {
                        iscsi_opts |= BIT_4;
-                       idx = (ddb_entry->fw_ddb_index * 2) + 1;
-                       if (idx > max_chap_entries) {
-                               ql4_printk(KERN_ERR, ha,
-                                          "%s: Invalid ddb or bidi chap "
-                                          "index\n", __func__);
-                               rval  = -EINVAL;
-                               goto exit_set_param;
-                       }
-                       rval = qla4xxx_set_chap(ha, sess->username_in,
-                                               sess->password_in, idx, 0);
+
+                       rval = qla4xxx_get_chap_index(ha, sess->username_in,
+                                                     sess->password_in,
+                                                     BIDI_CHAP, &idx);
                        if (rval)
                                goto exit_set_param;
                }
@@ -1665,3 +1757,104 @@ int qla4xxx_get_mgmt_data(struct scsi_qla_host *ha, uint16_t fw_ddb_index,
        }
        return status;
 }
+
+int qla4xxx_get_ip_state(struct scsi_qla_host *ha, uint32_t acb_idx,
+                        uint32_t ip_idx, uint32_t *sts)
+{
+       uint32_t mbox_cmd[MBOX_REG_COUNT];
+       uint32_t mbox_sts[MBOX_REG_COUNT];
+       int status = QLA_SUCCESS;
+
+       memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+       memset(&mbox_sts, 0, sizeof(mbox_sts));
+       mbox_cmd[0] = MBOX_CMD_GET_IP_ADDR_STATE;
+       mbox_cmd[1] = acb_idx;
+       mbox_cmd[2] = ip_idx;
+
+       status = qla4xxx_mailbox_command(ha, 3, 8, &mbox_cmd[0], &mbox_sts[0]);
+       if (status != QLA_SUCCESS) {
+               DEBUG2(ql4_printk(KERN_WARNING, ha,  "%s: "
+                                 "MBOX_CMD_GET_IP_ADDR_STATE failed w/ "
+                                 "status %04X\n", __func__, mbox_sts[0]));
+       }
+       memcpy(sts, mbox_sts, sizeof(mbox_sts));
+       return status;
+}
+
+int qla4xxx_get_nvram(struct scsi_qla_host *ha, dma_addr_t nvram_dma,
+                     uint32_t offset, uint32_t size)
+{
+       int status = QLA_SUCCESS;
+       uint32_t mbox_cmd[MBOX_REG_COUNT];
+       uint32_t mbox_sts[MBOX_REG_COUNT];
+
+       memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+       memset(&mbox_sts, 0, sizeof(mbox_sts));
+
+       mbox_cmd[0] = MBOX_CMD_GET_NVRAM;
+       mbox_cmd[1] = LSDW(nvram_dma);
+       mbox_cmd[2] = MSDW(nvram_dma);
+       mbox_cmd[3] = offset;
+       mbox_cmd[4] = size;
+
+       status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0],
+                                        &mbox_sts[0]);
+       if (status != QLA_SUCCESS) {
+               DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed "
+                                 "status %04X\n", ha->host_no, __func__,
+                                 mbox_sts[0]));
+       }
+       return status;
+}
+
+int qla4xxx_set_nvram(struct scsi_qla_host *ha, dma_addr_t nvram_dma,
+                     uint32_t offset, uint32_t size)
+{
+       int status = QLA_SUCCESS;
+       uint32_t mbox_cmd[MBOX_REG_COUNT];
+       uint32_t mbox_sts[MBOX_REG_COUNT];
+
+       memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+       memset(&mbox_sts, 0, sizeof(mbox_sts));
+
+       mbox_cmd[0] = MBOX_CMD_SET_NVRAM;
+       mbox_cmd[1] = LSDW(nvram_dma);
+       mbox_cmd[2] = MSDW(nvram_dma);
+       mbox_cmd[3] = offset;
+       mbox_cmd[4] = size;
+
+       status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0],
+                                        &mbox_sts[0]);
+       if (status != QLA_SUCCESS) {
+               DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed "
+                                 "status %04X\n", ha->host_no, __func__,
+                                 mbox_sts[0]));
+       }
+       return status;
+}
+
+int qla4xxx_restore_factory_defaults(struct scsi_qla_host *ha,
+                                    uint32_t region, uint32_t field0,
+                                    uint32_t field1)
+{
+       int status = QLA_SUCCESS;
+       uint32_t mbox_cmd[MBOX_REG_COUNT];
+       uint32_t mbox_sts[MBOX_REG_COUNT];
+
+       memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+       memset(&mbox_sts, 0, sizeof(mbox_sts));
+
+       mbox_cmd[0] = MBOX_CMD_RESTORE_FACTORY_DEFAULTS;
+       mbox_cmd[3] = region;
+       mbox_cmd[4] = field0;
+       mbox_cmd[5] = field1;
+
+       status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 3, &mbox_cmd[0],
+                                        &mbox_sts[0]);
+       if (status != QLA_SUCCESS) {
+               DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed "
+                                 "status %04X\n", ha->host_no, __func__,
+                                 mbox_sts[0]));
+       }
+       return status;
+}