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 32e40cb..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));
 
@@ -1214,61 +1228,6 @@ int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t ddb_index,
        return status;
 }
 
-int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port)
-{
-       struct dev_db_entry *fw_ddb_entry;
-       dma_addr_t fw_ddb_entry_dma;
-       uint32_t ddb_index;
-       uint32_t mbx_sts;
-       uint32_t options = 0;
-       int ret_val = QLA_SUCCESS;
-
-
-       fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev,
-                                         sizeof(*fw_ddb_entry),
-                                         &fw_ddb_entry_dma, GFP_KERNEL);
-       if (!fw_ddb_entry) {
-               DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
-                             ha->host_no, __func__));
-               ret_val = QLA_ERROR;
-               goto exit_send_tgts_no_free;
-       }
-
-       ret_val = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma);
-       if (ret_val != QLA_SUCCESS)
-               goto exit_send_tgts;
-
-       ret_val = qla4xxx_req_ddb_entry(ha, &ddb_index, &mbx_sts);
-       if (ret_val != QLA_SUCCESS)
-               goto exit_send_tgts;
-
-       memset(fw_ddb_entry->iscsi_alias, 0,
-              sizeof(fw_ddb_entry->iscsi_alias));
-
-       memset(fw_ddb_entry->iscsi_name, 0,
-              sizeof(fw_ddb_entry->iscsi_name));
-
-       memset(fw_ddb_entry->ip_addr, 0, sizeof(fw_ddb_entry->ip_addr));
-       memset(fw_ddb_entry->tgt_addr, 0,
-              sizeof(fw_ddb_entry->tgt_addr));
-
-       fw_ddb_entry->options = (DDB_OPT_DISC_SESSION | DDB_OPT_TARGET);
-       fw_ddb_entry->port = cpu_to_le16(ntohs(port));
-
-       fw_ddb_entry->ip_addr[0] = *ip;
-       fw_ddb_entry->ip_addr[1] = *(ip + 1);
-       fw_ddb_entry->ip_addr[2] = *(ip + 2);
-       fw_ddb_entry->ip_addr[3] = *(ip + 3);
-
-       ret_val = qla4xxx_set_ddb_entry(ha, ddb_index, fw_ddb_entry_dma, NULL);
-
-exit_send_tgts:
-       dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
-                         fw_ddb_entry, fw_ddb_entry_dma);
-exit_send_tgts_no_free:
-       return ret_val;
-}
-
 int qla4xxx_clear_ddb_entry(struct scsi_qla_host *ha, uint32_t ddb_index)
 {
        int status;
@@ -1317,6 +1276,93 @@ int qla4xxx_set_flash(struct scsi_qla_host *ha, dma_addr_t dma_addr,
        return status;
 }
 
+int qla4xxx_bootdb_by_index(struct scsi_qla_host *ha,
+                           struct dev_db_entry *fw_ddb_entry,
+                           dma_addr_t fw_ddb_entry_dma, uint16_t ddb_index)
+{
+       uint32_t dev_db_start_offset = FLASH_OFFSET_DB_INFO;
+       uint32_t dev_db_end_offset;
+       int status = QLA_ERROR;
+
+       memset(fw_ddb_entry, 0, sizeof(*fw_ddb_entry));
+
+       dev_db_start_offset += (ddb_index * sizeof(*fw_ddb_entry));
+       dev_db_end_offset = FLASH_OFFSET_DB_END;
+
+       if (dev_db_start_offset > dev_db_end_offset) {
+               DEBUG2(ql4_printk(KERN_ERR, ha,
+                                 "%s:Invalid DDB index %d", __func__,
+                                 ddb_index));
+               goto exit_bootdb_failed;
+       }
+
+       if (qla4xxx_get_flash(ha, fw_ddb_entry_dma, dev_db_start_offset,
+                             sizeof(*fw_ddb_entry)) != QLA_SUCCESS) {
+               ql4_printk(KERN_ERR, ha, "scsi%ld: %s: Get Flash"
+                          "failed\n", ha->host_no, __func__);
+               goto exit_bootdb_failed;
+       }
+
+       if (fw_ddb_entry->cookie == DDB_VALID_COOKIE)
+               status = QLA_SUCCESS;
+
+exit_bootdb_failed:
+       return status;
+}
+
+int qla4xxx_get_chap(struct scsi_qla_host *ha, char *username, char *password,
+                    uint16_t idx)
+{
+       int ret = 0;
+       int rval = QLA_ERROR;
+       uint32_t offset = 0, chap_size;
+       struct ql4_chap_table *chap_table;
+       dma_addr_t chap_dma;
+
+       chap_table = dma_pool_alloc(ha->chap_dma_pool, GFP_KERNEL, &chap_dma);
+       if (chap_table == NULL) {
+               ret = -ENOMEM;
+               goto exit_get_chap;
+       }
+
+       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, chap_size);
+       if (rval != QLA_SUCCESS) {
+               ret = -EINVAL;
+               goto exit_get_chap;
+       }
+
+       DEBUG2(ql4_printk(KERN_INFO, ha, "Chap Cookie: x%x\n",
+               __le16_to_cpu(chap_table->cookie)));
+
+       if (__le16_to_cpu(chap_table->cookie) != CHAP_VALID_COOKIE) {
+               ql4_printk(KERN_ERR, ha, "No valid chap entry found\n");
+               goto exit_get_chap;
+       }
+
+       strncpy(password, chap_table->secret, QL4_CHAP_MAX_SECRET_LEN);
+       strncpy(username, chap_table->name, QL4_CHAP_MAX_NAME_LEN);
+       chap_table->cookie = __constant_cpu_to_le16(CHAP_VALID_COOKIE);
+
+exit_get_chap:
+       dma_pool_free(ha->chap_dma_pool, chap_table, chap_dma);
+       return ret;
+}
+
 static int qla4xxx_set_chap(struct scsi_qla_host *ha, char *username,
                            char *password, uint16_t idx, int bidi)
 {
@@ -1341,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;
@@ -1353,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,
@@ -1399,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) {
@@ -1462,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);
@@ -1531,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;
 
@@ -1561,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;
                }
@@ -1643,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;
+}