diff options
Diffstat (limited to 'drivers/scsi/qla4xxx/ql4_mbx.c')
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_mbx.c | 360 |
1 files changed, 333 insertions, 27 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index ea04b6cecfa..32e40cb534f 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -477,10 +477,11 @@ int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha) init_fw_cb->fw_options &= __constant_cpu_to_le16(~FWOPT_TARGET_MODE); - /* Set bit for "serialize task mgmt" all other bits need to be zero */ init_fw_cb->add_fw_options = 0; init_fw_cb->add_fw_options |= - __constant_cpu_to_le16(SERIALIZE_TASK_MGMT); + __constant_cpu_to_le16(ADFWOPT_SERIALIZE_TASK_MGMT); + init_fw_cb->add_fw_options |= + __constant_cpu_to_le16(ADFWOPT_AUTOCONN_DISABLE); if (qla4xxx_set_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma) != QLA_SUCCESS) { @@ -706,19 +707,38 @@ exit_get_fwddb: return status; } +int qla4xxx_conn_open(struct scsi_qla_host *ha, uint16_t fw_ddb_index) +{ + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + int status; + + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + + mbox_cmd[0] = MBOX_CMD_CONN_OPEN; + mbox_cmd[1] = fw_ddb_index; + + status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 2, &mbox_cmd[0], + &mbox_sts[0]); + DEBUG2(ql4_printk(KERN_INFO, ha, + "%s: status = %d mbx0 = 0x%x mbx1 = 0x%x\n", + __func__, status, mbox_sts[0], mbox_sts[1])); + return status; +} + /** * qla4xxx_set_fwddb_entry - sets a ddb entry. * @ha: Pointer to host adapter structure. * @fw_ddb_index: Firmware's device database index - * @fw_ddb_entry: Pointer to firmware's ddb entry structure, or NULL. + * @fw_ddb_entry_dma: dma address of ddb entry + * @mbx_sts: mailbox 0 to be returned or NULL * * This routine initializes or updates the adapter's device database - * entry for the specified device. It also triggers a login for the - * specified device. Therefore, it may also be used as a secondary - * login routine when a NULL pointer is specified for the fw_ddb_entry. + * entry for the specified device. **/ int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index, - dma_addr_t fw_ddb_entry_dma) + dma_addr_t fw_ddb_entry_dma, uint32_t *mbx_sts) { uint32_t mbox_cmd[MBOX_REG_COUNT]; uint32_t mbox_sts[MBOX_REG_COUNT]; @@ -737,13 +757,41 @@ int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index, mbox_cmd[4] = sizeof(struct dev_db_entry); status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], - &mbox_sts[0]); + &mbox_sts[0]); + if (mbx_sts) + *mbx_sts = mbox_sts[0]; DEBUG2(printk("scsi%ld: %s: status=%d mbx0=0x%x mbx4=0x%x\n", ha->host_no, __func__, status, mbox_sts[0], mbox_sts[4]);) return status; } +int qla4xxx_session_logout_ddb(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry, int options) +{ + int status; + 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_CONN_CLOSE_SESS_LOGOUT; + mbox_cmd[1] = ddb_entry->fw_ddb_index; + mbox_cmd[3] = options; + + status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 2, &mbox_cmd[0], + &mbox_sts[0]); + if (status != QLA_SUCCESS) { + DEBUG2(ql4_printk(KERN_INFO, ha, + "%s: MBOX_CMD_CONN_CLOSE_SESS_LOGOUT " + "failed sts %04X %04X", __func__, + mbox_sts[0], mbox_sts[1])); + } + + return status; +} + /** * qla4xxx_get_crash_record - retrieves crash record. * @ha: Pointer to host adapter structure. @@ -1119,7 +1167,7 @@ exit_about_fw: return status; } -static int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, +static int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, uint32_t options, dma_addr_t dma_addr) { uint32_t mbox_cmd[MBOX_REG_COUNT]; @@ -1129,6 +1177,7 @@ static int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, memset(&mbox_sts, 0, sizeof(mbox_sts)); mbox_cmd[0] = MBOX_CMD_GET_DATABASE_ENTRY_DEFAULTS; + mbox_cmd[1] = options; mbox_cmd[2] = LSDW(dma_addr); mbox_cmd[3] = MSDW(dma_addr); @@ -1141,8 +1190,10 @@ static int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, return QLA_SUCCESS; } -static int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t *ddb_index) +int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t ddb_index, + uint32_t *mbx_sts) { + int status; uint32_t mbox_cmd[MBOX_REG_COUNT]; uint32_t mbox_sts[MBOX_REG_COUNT]; @@ -1150,30 +1201,26 @@ static int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t *ddb_index) memset(&mbox_sts, 0, sizeof(mbox_sts)); mbox_cmd[0] = MBOX_CMD_REQUEST_DATABASE_ENTRY; - mbox_cmd[1] = MAX_PRST_DEV_DB_ENTRIES; + mbox_cmd[1] = ddb_index; - if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 3, &mbox_cmd[0], &mbox_sts[0]) != - QLA_SUCCESS) { - if (mbox_sts[0] == MBOX_STS_COMMAND_ERROR) { - *ddb_index = mbox_sts[2]; - } else { - DEBUG2(printk("scsi%ld: %s: failed status %04X\n", - ha->host_no, __func__, mbox_sts[0])); - return QLA_ERROR; - } - } else { - *ddb_index = MAX_PRST_DEV_DB_ENTRIES; + 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, "%s: failed status %04X\n", + __func__, mbox_sts[0])); } - return QLA_SUCCESS; + *mbx_sts = mbox_sts[0]; + 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; @@ -1187,11 +1234,11 @@ int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port) goto exit_send_tgts_no_free; } - ret_val = qla4xxx_get_default_ddb(ha, fw_ddb_entry_dma); + 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); + ret_val = qla4xxx_req_ddb_entry(ha, &ddb_index, &mbx_sts); if (ret_val != QLA_SUCCESS) goto exit_send_tgts; @@ -1213,7 +1260,7 @@ int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port) 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); + 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), @@ -1222,6 +1269,28 @@ exit_send_tgts_no_free: return ret_val; } +int qla4xxx_clear_ddb_entry(struct scsi_qla_host *ha, uint32_t ddb_index) +{ + int status; + 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_CLEAR_DATABASE_ENTRY; + mbox_cmd[1] = ddb_index; + + status = qla4xxx_mailbox_command(ha, 2, 1, &mbox_cmd[0], + &mbox_sts[0]); + if (status != QLA_SUCCESS) { + DEBUG2(ql4_printk(KERN_ERR, ha, "%s: failed status %04X\n", + __func__, mbox_sts[0])); + } + + return status; +} + int qla4xxx_set_flash(struct scsi_qla_host *ha, dma_addr_t dma_addr, uint32_t offset, uint32_t length, uint32_t options) { @@ -1248,6 +1317,42 @@ int qla4xxx_set_flash(struct scsi_qla_host *ha, dma_addr_t dma_addr, return status; } +static int qla4xxx_set_chap(struct scsi_qla_host *ha, char *username, + char *password, uint16_t idx, int bidi) +{ + int ret = 0; + int rval = QLA_ERROR; + uint32_t offset = 0; + 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_set_chap; + } + + memset(chap_table, 0, sizeof(struct ql4_chap_table)); + if (bidi) + chap_table->flags |= BIT_6; /* peer */ + else + chap_table->flags |= BIT_7; /* local */ + chap_table->secret_len = strlen(password); + 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)); + rval = qla4xxx_set_flash(ha, chap_dma, offset, + sizeof(struct ql4_chap_table), + FLASH_OPT_RMW_COMMIT); + dma_pool_free(ha->chap_dma_pool, chap_table, chap_dma); + if (rval != QLA_SUCCESS) + ret = -EINVAL; + +exit_set_chap: + return ret; +} + int qla4xxx_conn_close_sess_logout(struct scsi_qla_host *ha, uint16_t fw_ddb_index, uint16_t connection_id, @@ -1337,3 +1442,204 @@ int qla4xxx_set_acb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, } return status; } + +int qla4xxx_set_param_ddbentry(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry, + struct iscsi_cls_conn *cls_conn, + uint32_t *mbx_sts) +{ + struct dev_db_entry *fw_ddb_entry; + struct iscsi_conn *conn; + struct iscsi_session *sess; + struct qla_conn *qla_conn; + struct sockaddr *dst_addr; + dma_addr_t fw_ddb_entry_dma; + int status = QLA_SUCCESS; + int rval = 0; + struct sockaddr_in *addr; + struct sockaddr_in6 *addr6; + char *ip; + 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); + if (!fw_ddb_entry) { + DEBUG2(ql4_printk(KERN_ERR, ha, + "%s: Unable to allocate dma buffer.\n", + __func__)); + rval = -ENOMEM; + goto exit_set_param_no_free; + } + + conn = cls_conn->dd_data; + qla_conn = conn->dd_data; + sess = conn->session; + dst_addr = &qla_conn->qla_ep->dst_addr; + + if (dst_addr->sa_family == AF_INET6) + options |= IPV6_DEFAULT_DDB_ENTRY; + + status = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma); + if (status == QLA_ERROR) { + rval = -EINVAL; + goto exit_set_param; + } + + iscsi_opts = le16_to_cpu(fw_ddb_entry->iscsi_options); + 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)); + + if (sess->targetname != NULL) { + memcpy(fw_ddb_entry->iscsi_name, sess->targetname, + min(strlen(sess->targetname), + 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_TARGET | DDB_OPT_AUTO_SENDTGTS_DISABLE; + + if (dst_addr->sa_family == AF_INET) { + addr = (struct sockaddr_in *)dst_addr; + ip = (char *)&addr->sin_addr; + memcpy(fw_ddb_entry->ip_addr, ip, IP_ADDR_LEN); + fw_ddb_entry->port = cpu_to_le16(ntohs(addr->sin_port)); + DEBUG2(ql4_printk(KERN_INFO, ha, + "%s: Destination Address [%pI4]: index [%d]\n", + __func__, fw_ddb_entry->ip_addr, + ddb_entry->fw_ddb_index)); + } else if (dst_addr->sa_family == AF_INET6) { + addr6 = (struct sockaddr_in6 *)dst_addr; + ip = (char *)&addr6->sin6_addr; + memcpy(fw_ddb_entry->ip_addr, ip, IPv6_ADDR_LEN); + fw_ddb_entry->port = cpu_to_le16(ntohs(addr6->sin6_port)); + fw_ddb_entry->options |= DDB_OPT_IPV6_DEVICE; + DEBUG2(ql4_printk(KERN_INFO, ha, + "%s: Destination Address [%pI6]: index [%d]\n", + __func__, fw_ddb_entry->ip_addr, + ddb_entry->fw_ddb_index)); + } else { + ql4_printk(KERN_ERR, ha, + "%s: Failed to get IP Address\n", + __func__); + rval = -EINVAL; + 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); + if (rval) + goto exit_set_param; + + fw_ddb_entry->chap_tbl_idx = cpu_to_le16(idx); + } + } + + if (sess->username_in != NULL && sess->password_in != NULL) { + /* 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); + if (rval) + goto exit_set_param; + } + } + + if (sess->initial_r2t_en) + iscsi_opts |= BIT_10; + + if (sess->imm_data_en) + iscsi_opts |= BIT_11; + + fw_ddb_entry->iscsi_options = cpu_to_le16(iscsi_opts); + + if (conn->max_recv_dlength) + fw_ddb_entry->iscsi_max_rcv_data_seg_len = + __constant_cpu_to_le16((conn->max_recv_dlength / BYTE_UNITS)); + + if (sess->max_r2t) + fw_ddb_entry->iscsi_max_outsnd_r2t = cpu_to_le16(sess->max_r2t); + + if (sess->first_burst) + fw_ddb_entry->iscsi_first_burst_len = + __constant_cpu_to_le16((sess->first_burst / BYTE_UNITS)); + + if (sess->max_burst) + fw_ddb_entry->iscsi_max_burst_len = + __constant_cpu_to_le16((sess->max_burst / BYTE_UNITS)); + + if (sess->time2wait) + fw_ddb_entry->iscsi_def_time2wait = + cpu_to_le16(sess->time2wait); + + if (sess->time2retain) + fw_ddb_entry->iscsi_def_time2retain = + cpu_to_le16(sess->time2retain); + + status = qla4xxx_set_ddb_entry(ha, ddb_entry->fw_ddb_index, + fw_ddb_entry_dma, mbx_sts); + + if (status != QLA_SUCCESS) + rval = -EINVAL; +exit_set_param: + dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + fw_ddb_entry, fw_ddb_entry_dma); +exit_set_param_no_free: + return rval; +} + +int qla4xxx_get_mgmt_data(struct scsi_qla_host *ha, uint16_t fw_ddb_index, + uint16_t stats_size, dma_addr_t stats_dma) +{ + 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[0]) * MBOX_REG_COUNT); + memset(mbox_sts, 0, sizeof(mbox_sts[0]) * MBOX_REG_COUNT); + mbox_cmd[0] = MBOX_CMD_GET_MANAGEMENT_DATA; + mbox_cmd[1] = fw_ddb_index; + mbox_cmd[2] = LSDW(stats_dma); + mbox_cmd[3] = MSDW(stats_dma); + mbox_cmd[4] = stats_size; + + status = qla4xxx_mailbox_command(ha, 5, 1, &mbox_cmd[0], &mbox_sts[0]); + if (status != QLA_SUCCESS) { + DEBUG2(ql4_printk(KERN_WARNING, ha, + "%s: MBOX_CMD_GET_MANAGEMENT_DATA " + "failed w/ status %04X\n", __func__, + mbox_sts[0])); + } + return status; +} |