[SCSI] qla4xxx: Boot from SAN support for open-iscsi

Hook qla4xxx in fw boot sysfs interface so iscsi tools
can use the info to create boot sessions.

Signed-off-by: Manish Rangankar <manish.rangankar@qlogic.com>
Signed-off-by: Vikas Chaudhary <vikas.chaudhary@qlogic.com>
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
Manish Rangankar 2011-07-25 13:48:55 -05:00 committed by James Bottomley
parent 0e7e85019c
commit 2a991c2159
7 changed files with 650 additions and 2 deletions

View file

@ -276,6 +276,8 @@ struct ql82xx_hw_data {
uint32_t flt_region_boot;
uint32_t flt_region_bootload;
uint32_t flt_region_fw;
uint32_t flt_iscsi_param;
uint32_t reserved;
};
@ -343,6 +345,41 @@ struct ipaddress_config {
struct in6_addr ipv6_default_router_addr;
};
#define QL4_CHAP_MAX_NAME_LEN 256
#define QL4_CHAP_MAX_SECRET_LEN 100
struct ql4_chap_format {
u8 intr_chap_name[QL4_CHAP_MAX_NAME_LEN];
u8 intr_secret[QL4_CHAP_MAX_SECRET_LEN];
u8 target_chap_name[QL4_CHAP_MAX_NAME_LEN];
u8 target_secret[QL4_CHAP_MAX_SECRET_LEN];
u16 intr_chap_name_length;
u16 intr_secret_length;
u16 target_chap_name_length;
u16 target_secret_length;
};
struct ip_address_format {
u8 ip_type;
u8 ip_address[16];
};
struct ql4_conn_info {
u16 dest_port;
struct ip_address_format dest_ipaddr;
struct ql4_chap_format chap;
};
struct ql4_boot_session_info {
u8 target_name[224];
struct ql4_conn_info conn_list[1];
};
struct ql4_boot_tgt_info {
struct ql4_boot_session_info boot_pri_sess;
struct ql4_boot_session_info boot_sec_sess;
};
/*
* Linux Host Adapter structure
*/
@ -444,7 +481,7 @@ struct scsi_qla_host {
/* --- From FlashSysInfo --- */
uint8_t my_mac[MAC_ADDR_LEN];
uint8_t serial_number[16];
uint16_t port_num;
/* --- From GetFwState --- */
uint32_t firmware_state;
uint32_t addl_fw_state;
@ -569,6 +606,9 @@ struct scsi_qla_host {
#define CHAP_DMA_BLOCK_SIZE 512
struct workqueue_struct *task_wq;
unsigned long ddb_idx_map[MAX_DDB_ENTRIES / BITS_PER_LONG];
#define SYSFS_FLAG_FW_SEL_BOOT 2
struct iscsi_boot_kset *boot_kset;
struct ql4_boot_tgt_info boot_tgt;
};
struct ql4_task_data {

View file

@ -146,6 +146,13 @@ struct isp_reg {
#define QL4022_NVRAM_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (10+16))
#define QL4022_FLASH_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (13+16))
/* nvram address for 4032 */
#define NVRAM_PORT0_BOOT_MODE 0x03b1
#define NVRAM_PORT0_BOOT_PRI_TGT 0x03b2
#define NVRAM_PORT0_BOOT_SEC_TGT 0x03bb
#define NVRAM_PORT1_BOOT_MODE 0x07b1
#define NVRAM_PORT1_BOOT_PRI_TGT 0x07b2
#define NVRAM_PORT1_BOOT_SEC_TGT 0x07bb
/* Page # defines for 4022 */
@ -298,6 +305,7 @@ struct qla_flt_header {
#define FLT_REG_FW_82 0x74
#define FLT_REG_GOLD_FW_82 0x75
#define FLT_REG_BOOT_CODE_82 0x78
#define FLT_REG_ISCSI_PARAM 0x65
struct qla_flt_region {
uint32_t code;
@ -733,7 +741,10 @@ struct dev_db_entry {
uint8_t tcp_rcv_wsf; /* 1C7 */
uint32_t stat_sn; /* 1C8-1CB */
uint32_t exp_stat_sn; /* 1CC-1CF */
uint8_t res6[0x30]; /* 1D0-1FF */
uint8_t res6[0x2b]; /* 1D0-1FB */
#define DDB_VALID_COOKIE 0x9034
uint16_t cookie; /* 1FC-1FD */
uint16_t len; /* 1FE-1FF */
};
/*************************************************************************/
@ -745,6 +756,14 @@ struct dev_db_entry {
#define FLASH_EOF_OFFSET (FLASH_DEFAULTBLOCKSIZE-8) /* 4 bytes
* for EOF
* signature */
#define FLASH_RAW_ACCESS_ADDR 0x8e000000
#define BOOT_PARAM_OFFSET_PORT0 0x3b0
#define BOOT_PARAM_OFFSET_PORT1 0x7b0
#define FLASH_OFFSET_DB_INFO 0x05000000
#define FLASH_OFFSET_DB_END (FLASH_OFFSET_DB_INFO + 0x7fff)
struct sys_info_phys_addr {
uint8_t address[6]; /* 00-05 */

View file

@ -60,6 +60,7 @@ int qla4xxx_get_acb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
uint32_t *mbox_sts, dma_addr_t acb_dma);
void qla4xxx_mark_device_missing(struct iscsi_cls_session *cls_session);
u16 rd_nvram_word(struct scsi_qla_host *ha, int offset);
u8 rd_nvram_byte(struct scsi_qla_host *ha, int offset);
void qla4xxx_get_crash_record(struct scsi_qla_host *ha);
int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host *ha);
int qla4xxx_about_firmware(struct scsi_qla_host *ha);
@ -154,6 +155,12 @@ int qla4xxx_get_mgmt_data(struct scsi_qla_host *ha, uint16_t fw_ddb_index,
uint16_t stats_size, dma_addr_t stats_dma);
void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha,
struct ddb_entry *ddb_entry);
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);
int qla4xxx_get_chap(struct scsi_qla_host *ha, char *username,
char *password, uint16_t idx);
/* BSG Functions */
int qla4xxx_bsg_request(struct bsg_job *bsg_job);
int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job);

View file

@ -1262,6 +1262,83 @@ 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;
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;
}
memset(chap_table, 0, sizeof(struct ql4_chap_table));
offset = 0x06000000 | (idx * sizeof(struct ql4_chap_table));
rval = qla4xxx_get_flash(ha, chap_dma, offset,
sizeof(struct ql4_chap_table));
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)
{

View file

@ -156,6 +156,27 @@ u16 rd_nvram_word(struct scsi_qla_host * ha, int offset)
return val;
}
u8 rd_nvram_byte(struct scsi_qla_host *ha, int offset)
{
u16 val = 0;
u8 rval = 0;
int index = 0;
if (offset & 0x1)
index = (offset - 1) / 2;
else
index = offset / 2;
val = le16_to_cpu(rd_nvram_word(ha, index));
if (offset & 0x1)
rval = (u8)((val & 0xff00) >> 8);
else
rval = (u8)((val & 0x00ff));
return rval;
}
int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host * ha)
{
int status = QLA_ERROR;

View file

@ -2020,6 +2020,9 @@ qla4_8xxx_get_flt_info(struct scsi_qla_host *ha, uint32_t flt_addr)
case FLT_REG_BOOTLOAD_82:
hw->flt_region_bootload = start;
break;
case FLT_REG_ISCSI_PARAM:
hw->flt_iscsi_param = start;
break;
}
}
goto done;
@ -2258,6 +2261,7 @@ int qla4_8xxx_get_sys_info(struct scsi_qla_host *ha)
}
/* Save M.A.C. address & serial_number */
ha->port_num = sys_info->port_num;
memcpy(ha->my_mac, &sys_info->mac_addr[0],
min(sizeof(ha->my_mac), sizeof(sys_info->mac_addr)));
memcpy(ha->serial_number, &sys_info->serial_number,

View file

@ -6,6 +6,8 @@
*/
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/blkdev.h>
#include <linux/iscsi_boot_sysfs.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsicam.h>
@ -2551,6 +2553,477 @@ uint16_t qla4_8xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
return (uint16_t)le32_to_cpu(readl(&ha->qla4_8xxx_reg->rsp_q_in));
}
static ssize_t qla4xxx_show_boot_eth_info(void *data, int type, char *buf)
{
struct scsi_qla_host *ha = data;
char *str = buf;
int rc;
switch (type) {
case ISCSI_BOOT_ETH_FLAGS:
rc = sprintf(str, "%d\n", SYSFS_FLAG_FW_SEL_BOOT);
break;
case ISCSI_BOOT_ETH_INDEX:
rc = sprintf(str, "0\n");
break;
case ISCSI_BOOT_ETH_MAC:
rc = sysfs_format_mac(str, ha->my_mac,
MAC_ADDR_LEN);
break;
default:
rc = -ENOSYS;
break;
}
return rc;
}
static mode_t qla4xxx_eth_get_attr_visibility(void *data, int type)
{
int rc;
switch (type) {
case ISCSI_BOOT_ETH_FLAGS:
case ISCSI_BOOT_ETH_MAC:
case ISCSI_BOOT_ETH_INDEX:
rc = S_IRUGO;
break;
default:
rc = 0;
break;
}
return rc;
}
static ssize_t qla4xxx_show_boot_ini_info(void *data, int type, char *buf)
{
struct scsi_qla_host *ha = data;
char *str = buf;
int rc;
switch (type) {
case ISCSI_BOOT_INI_INITIATOR_NAME:
rc = sprintf(str, "%s\n", ha->name_string);
break;
default:
rc = -ENOSYS;
break;
}
return rc;
}
static mode_t qla4xxx_ini_get_attr_visibility(void *data, int type)
{
int rc;
switch (type) {
case ISCSI_BOOT_INI_INITIATOR_NAME:
rc = S_IRUGO;
break;
default:
rc = 0;
break;
}
return rc;
}
static ssize_t
qla4xxx_show_boot_tgt_info(struct ql4_boot_session_info *boot_sess, int type,
char *buf)
{
struct ql4_conn_info *boot_conn = &boot_sess->conn_list[0];
char *str = buf;
int rc;
switch (type) {
case ISCSI_BOOT_TGT_NAME:
rc = sprintf(buf, "%s\n", (char *)&boot_sess->target_name);
break;
case ISCSI_BOOT_TGT_IP_ADDR:
if (boot_sess->conn_list[0].dest_ipaddr.ip_type == 0x1)
rc = sprintf(buf, "%pI4\n",
&boot_conn->dest_ipaddr.ip_address);
else
rc = sprintf(str, "%pI6\n",
&boot_conn->dest_ipaddr.ip_address);
break;
case ISCSI_BOOT_TGT_PORT:
rc = sprintf(str, "%d\n", boot_conn->dest_port);
break;
case ISCSI_BOOT_TGT_CHAP_NAME:
rc = sprintf(str, "%.*s\n",
boot_conn->chap.target_chap_name_length,
(char *)&boot_conn->chap.target_chap_name);
break;
case ISCSI_BOOT_TGT_CHAP_SECRET:
rc = sprintf(str, "%.*s\n",
boot_conn->chap.target_secret_length,
(char *)&boot_conn->chap.target_secret);
break;
case ISCSI_BOOT_TGT_REV_CHAP_NAME:
rc = sprintf(str, "%.*s\n",
boot_conn->chap.intr_chap_name_length,
(char *)&boot_conn->chap.intr_chap_name);
break;
case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
rc = sprintf(str, "%.*s\n",
boot_conn->chap.intr_secret_length,
(char *)&boot_conn->chap.intr_secret);
break;
case ISCSI_BOOT_TGT_FLAGS:
rc = sprintf(str, "%d\n", SYSFS_FLAG_FW_SEL_BOOT);
break;
case ISCSI_BOOT_TGT_NIC_ASSOC:
rc = sprintf(str, "0\n");
break;
default:
rc = -ENOSYS;
break;
}
return rc;
}
static ssize_t qla4xxx_show_boot_tgt_pri_info(void *data, int type, char *buf)
{
struct scsi_qla_host *ha = data;
struct ql4_boot_session_info *boot_sess = &(ha->boot_tgt.boot_pri_sess);
return qla4xxx_show_boot_tgt_info(boot_sess, type, buf);
}
static ssize_t qla4xxx_show_boot_tgt_sec_info(void *data, int type, char *buf)
{
struct scsi_qla_host *ha = data;
struct ql4_boot_session_info *boot_sess = &(ha->boot_tgt.boot_sec_sess);
return qla4xxx_show_boot_tgt_info(boot_sess, type, buf);
}
static mode_t qla4xxx_tgt_get_attr_visibility(void *data, int type)
{
int rc;
switch (type) {
case ISCSI_BOOT_TGT_NAME:
case ISCSI_BOOT_TGT_IP_ADDR:
case ISCSI_BOOT_TGT_PORT:
case ISCSI_BOOT_TGT_CHAP_NAME:
case ISCSI_BOOT_TGT_CHAP_SECRET:
case ISCSI_BOOT_TGT_REV_CHAP_NAME:
case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
case ISCSI_BOOT_TGT_NIC_ASSOC:
case ISCSI_BOOT_TGT_FLAGS:
rc = S_IRUGO;
break;
default:
rc = 0;
break;
}
return rc;
}
static void qla4xxx_boot_release(void *data)
{
struct scsi_qla_host *ha = data;
scsi_host_put(ha->host);
}
static int get_fw_boot_info(struct scsi_qla_host *ha, uint16_t ddb_index[])
{
dma_addr_t buf_dma;
uint32_t addr, pri_addr, sec_addr;
uint32_t offset;
uint16_t func_num;
uint8_t val;
uint8_t *buf = NULL;
size_t size = 13 * sizeof(uint8_t);
int ret = QLA_SUCCESS;
func_num = PCI_FUNC(ha->pdev->devfn);
DEBUG2(ql4_printk(KERN_INFO, ha,
"%s: Get FW boot info for 0x%x func %d\n", __func__,
(is_qla4032(ha) ? PCI_DEVICE_ID_QLOGIC_ISP4032 :
PCI_DEVICE_ID_QLOGIC_ISP8022), func_num));
if (is_qla4032(ha)) {
if (func_num == 1) {
addr = NVRAM_PORT0_BOOT_MODE;
pri_addr = NVRAM_PORT0_BOOT_PRI_TGT;
sec_addr = NVRAM_PORT0_BOOT_SEC_TGT;
} else if (func_num == 3) {
addr = NVRAM_PORT1_BOOT_MODE;
pri_addr = NVRAM_PORT1_BOOT_PRI_TGT;
sec_addr = NVRAM_PORT1_BOOT_SEC_TGT;
} else {
ret = QLA_ERROR;
goto exit_boot_info;
}
/* Check Boot Mode */
val = rd_nvram_byte(ha, addr);
if (!(val & 0x07)) {
DEBUG2(ql4_printk(KERN_ERR, ha,
"%s: Failed Boot options : 0x%x\n",
__func__, val));
ret = QLA_ERROR;
goto exit_boot_info;
}
/* get primary valid target index */
val = rd_nvram_byte(ha, pri_addr);
if (val & BIT_7)
ddb_index[0] = (val & 0x7f);
else
ddb_index[0] = 0;
/* get secondary valid target index */
val = rd_nvram_byte(ha, sec_addr);
if (val & BIT_7)
ddb_index[1] = (val & 0x7f);
else
ddb_index[1] = 1;
} else if (is_qla8022(ha)) {
buf = dma_alloc_coherent(&ha->pdev->dev, size,
&buf_dma, GFP_KERNEL);
if (!buf) {
DEBUG2(ql4_printk(KERN_ERR, ha,
"%s: Unable to allocate dma buffer\n",
__func__));
ret = QLA_ERROR;
goto exit_boot_info;
}
if (ha->port_num == 0)
offset = BOOT_PARAM_OFFSET_PORT0;
else if (ha->port_num == 1)
offset = BOOT_PARAM_OFFSET_PORT1;
else {
ret = QLA_ERROR;
goto exit_boot_info_free;
}
addr = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_iscsi_param * 4) +
offset;
if (qla4xxx_get_flash(ha, buf_dma, addr,
13 * sizeof(uint8_t)) != QLA_SUCCESS) {
DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: Get Flash"
"failed\n", ha->host_no, __func__));
ret = QLA_ERROR;
goto exit_boot_info_free;
}
/* Check Boot Mode */
if (!(buf[1] & 0x07)) {
DEBUG2(ql4_printk(KERN_INFO, ha,
"Failed: Boot options : 0x%x\n",
buf[1]));
ret = QLA_ERROR;
goto exit_boot_info_free;
}
/* get primary valid target index */
if (buf[2] & BIT_7)
ddb_index[0] = buf[2] & 0x7f;
else
ddb_index[0] = 0;
/* get secondary valid target index */
if (buf[11] & BIT_7)
ddb_index[1] = buf[11] & 0x7f;
else
ddb_index[1] = 1;
} else {
ret = QLA_ERROR;
goto exit_boot_info;
}
DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Primary target ID %d, Secondary"
" target ID %d\n", __func__, ddb_index[0],
ddb_index[1]));
exit_boot_info_free:
dma_free_coherent(&ha->pdev->dev, size, buf, buf_dma);
exit_boot_info:
return ret;
}
static int qla4xxx_get_boot_target(struct scsi_qla_host *ha,
struct ql4_boot_session_info *boot_sess,
uint16_t ddb_index)
{
struct ql4_conn_info *boot_conn = &boot_sess->conn_list[0];
struct dev_db_entry *fw_ddb_entry;
dma_addr_t fw_ddb_entry_dma;
uint16_t idx;
uint16_t options;
int ret = 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(ql4_printk(KERN_ERR, ha,
"%s: Unable to allocate dma buffer.\n",
__func__));
ret = QLA_ERROR;
return ret;
}
if (qla4xxx_bootdb_by_index(ha, fw_ddb_entry,
fw_ddb_entry_dma, ddb_index)) {
DEBUG2(ql4_printk(KERN_ERR, ha,
"%s: Flash DDB read Failed\n", __func__));
ret = QLA_ERROR;
goto exit_boot_target;
}
/* Update target name and IP from DDB */
memcpy(boot_sess->target_name, fw_ddb_entry->iscsi_name,
min(sizeof(boot_sess->target_name),
sizeof(fw_ddb_entry->iscsi_name)));
options = le16_to_cpu(fw_ddb_entry->options);
if (options & DDB_OPT_IPV6_DEVICE) {
memcpy(&boot_conn->dest_ipaddr.ip_address,
&fw_ddb_entry->ip_addr[0], IPv6_ADDR_LEN);
} else {
boot_conn->dest_ipaddr.ip_type = 0x1;
memcpy(&boot_conn->dest_ipaddr.ip_address,
&fw_ddb_entry->ip_addr[0], IP_ADDR_LEN);
}
boot_conn->dest_port = le16_to_cpu(fw_ddb_entry->port);
/* update chap information */
idx = __le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
if (BIT_7 & le16_to_cpu(fw_ddb_entry->iscsi_options)) {
DEBUG2(ql4_printk(KERN_INFO, ha, "Setting chap\n"));
ret = qla4xxx_get_chap(ha, (char *)&boot_conn->chap.
target_chap_name,
(char *)&boot_conn->chap.target_secret,
idx);
if (ret) {
ql4_printk(KERN_ERR, ha, "Failed to set chap\n");
ret = QLA_ERROR;
goto exit_boot_target;
}
boot_conn->chap.target_chap_name_length = QL4_CHAP_MAX_NAME_LEN;
boot_conn->chap.target_secret_length = QL4_CHAP_MAX_SECRET_LEN;
}
if (BIT_4 & le16_to_cpu(fw_ddb_entry->iscsi_options)) {
DEBUG2(ql4_printk(KERN_INFO, ha, "Setting BIDI chap\n"));
ret = qla4xxx_get_chap(ha, (char *)&boot_conn->chap.
intr_chap_name,
(char *)&boot_conn->chap.intr_secret,
(idx + 1));
if (ret) {
ql4_printk(KERN_ERR, ha, "Failed to set BIDI chap\n");
ret = QLA_ERROR;
goto exit_boot_target;
}
boot_conn->chap.intr_chap_name_length = QL4_CHAP_MAX_NAME_LEN;
boot_conn->chap.intr_secret_length = QL4_CHAP_MAX_SECRET_LEN;
}
exit_boot_target:
dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
fw_ddb_entry, fw_ddb_entry_dma);
return ret;
}
static int qla4xxx_get_boot_info(struct scsi_qla_host *ha)
{
uint16_t ddb_index[2];
int ret = QLA_SUCCESS;
memset(ddb_index, 0, sizeof(ddb_index));
ret = get_fw_boot_info(ha, ddb_index);
if (ret != QLA_SUCCESS) {
DEBUG2(ql4_printk(KERN_ERR, ha,
"%s: Failed to set boot info.\n", __func__));
return ret;
}
ret = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_pri_sess),
ddb_index[0]);
if (ret != QLA_SUCCESS) {
DEBUG2(ql4_printk(KERN_ERR, ha, "%s: Failed to get "
"primary target\n", __func__));
}
ret = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_sec_sess),
ddb_index[1]);
if (ret != QLA_SUCCESS) {
DEBUG2(ql4_printk(KERN_ERR, ha, "%s: Failed to get "
"secondary target\n", __func__));
}
return ret;
}
static int qla4xxx_setup_boot_info(struct scsi_qla_host *ha)
{
struct iscsi_boot_kobj *boot_kobj;
if (qla4xxx_get_boot_info(ha) != QLA_SUCCESS)
return 0;
ha->boot_kset = iscsi_boot_create_host_kset(ha->host->host_no);
if (!ha->boot_kset)
goto kset_free;
if (!scsi_host_get(ha->host))
goto kset_free;
boot_kobj = iscsi_boot_create_target(ha->boot_kset, 0, ha,
qla4xxx_show_boot_tgt_pri_info,
qla4xxx_tgt_get_attr_visibility,
qla4xxx_boot_release);
if (!boot_kobj)
goto put_host;
if (!scsi_host_get(ha->host))
goto kset_free;
boot_kobj = iscsi_boot_create_target(ha->boot_kset, 1, ha,
qla4xxx_show_boot_tgt_sec_info,
qla4xxx_tgt_get_attr_visibility,
qla4xxx_boot_release);
if (!boot_kobj)
goto put_host;
if (!scsi_host_get(ha->host))
goto kset_free;
boot_kobj = iscsi_boot_create_initiator(ha->boot_kset, 0, ha,
qla4xxx_show_boot_ini_info,
qla4xxx_ini_get_attr_visibility,
qla4xxx_boot_release);
if (!boot_kobj)
goto put_host;
if (!scsi_host_get(ha->host))
goto kset_free;
boot_kobj = iscsi_boot_create_ethernet(ha->boot_kset, 0, ha,
qla4xxx_show_boot_eth_info,
qla4xxx_eth_get_attr_visibility,
qla4xxx_boot_release);
if (!boot_kobj)
goto put_host;
return 0;
put_host:
scsi_host_put(ha->host);
kset_free:
iscsi_boot_destroy_kset(ha->boot_kset);
return -ENOMEM;
}
/**
* qla4xxx_probe_adapter - callback function to probe HBA
* @pdev: pointer to pci_dev structure
@ -2758,6 +3231,10 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
ha->host_no, ha->firmware_version[0], ha->firmware_version[1],
ha->patch_number, ha->build_number);
if (qla4xxx_setup_boot_info(ha))
ql4_printk(KERN_ERR, ha, "%s:ISCSI boot info setup failed\n",
__func__);
qla4xxx_create_ifaces(ha);
return 0;
@ -2831,6 +3308,9 @@ static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev)
/* destroy iface from sysfs */
qla4xxx_destroy_ifaces(ha);
if (ha->boot_kset)
iscsi_boot_destroy_kset(ha->boot_kset);
scsi_remove_host(ha->host);
qla4xxx_free_adapter(ha);