diff options
author | Manish Rangankar <manish.rangankar@qlogic.com> | 2011-07-25 14:48:55 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2011-08-27 10:36:27 -0400 |
commit | 2a991c2159782b8d318ac9f88a36c22dda3e7185 (patch) | |
tree | 963cc3bec9517038458ad7e71b9a5d45ede4d360 /drivers | |
parent | 0e7e85019c2709131b10c5f34b602cc6b94fe782 (diff) |
[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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_def.h | 42 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_fw.h | 21 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_glbl.h | 7 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_mbx.c | 77 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_nvram.c | 21 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_nx.c | 4 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_os.c | 480 |
7 files changed, 650 insertions, 2 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index 6e2be9d963ac..30efb6c6594c 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h | |||
@@ -276,6 +276,8 @@ struct ql82xx_hw_data { | |||
276 | uint32_t flt_region_boot; | 276 | uint32_t flt_region_boot; |
277 | uint32_t flt_region_bootload; | 277 | uint32_t flt_region_bootload; |
278 | uint32_t flt_region_fw; | 278 | uint32_t flt_region_fw; |
279 | |||
280 | uint32_t flt_iscsi_param; | ||
279 | uint32_t reserved; | 281 | uint32_t reserved; |
280 | }; | 282 | }; |
281 | 283 | ||
@@ -343,6 +345,41 @@ struct ipaddress_config { | |||
343 | struct in6_addr ipv6_default_router_addr; | 345 | struct in6_addr ipv6_default_router_addr; |
344 | }; | 346 | }; |
345 | 347 | ||
348 | #define QL4_CHAP_MAX_NAME_LEN 256 | ||
349 | #define QL4_CHAP_MAX_SECRET_LEN 100 | ||
350 | |||
351 | struct ql4_chap_format { | ||
352 | u8 intr_chap_name[QL4_CHAP_MAX_NAME_LEN]; | ||
353 | u8 intr_secret[QL4_CHAP_MAX_SECRET_LEN]; | ||
354 | u8 target_chap_name[QL4_CHAP_MAX_NAME_LEN]; | ||
355 | u8 target_secret[QL4_CHAP_MAX_SECRET_LEN]; | ||
356 | u16 intr_chap_name_length; | ||
357 | u16 intr_secret_length; | ||
358 | u16 target_chap_name_length; | ||
359 | u16 target_secret_length; | ||
360 | }; | ||
361 | |||
362 | struct ip_address_format { | ||
363 | u8 ip_type; | ||
364 | u8 ip_address[16]; | ||
365 | }; | ||
366 | |||
367 | struct ql4_conn_info { | ||
368 | u16 dest_port; | ||
369 | struct ip_address_format dest_ipaddr; | ||
370 | struct ql4_chap_format chap; | ||
371 | }; | ||
372 | |||
373 | struct ql4_boot_session_info { | ||
374 | u8 target_name[224]; | ||
375 | struct ql4_conn_info conn_list[1]; | ||
376 | }; | ||
377 | |||
378 | struct ql4_boot_tgt_info { | ||
379 | struct ql4_boot_session_info boot_pri_sess; | ||
380 | struct ql4_boot_session_info boot_sec_sess; | ||
381 | }; | ||
382 | |||
346 | /* | 383 | /* |
347 | * Linux Host Adapter structure | 384 | * Linux Host Adapter structure |
348 | */ | 385 | */ |
@@ -444,7 +481,7 @@ struct scsi_qla_host { | |||
444 | /* --- From FlashSysInfo --- */ | 481 | /* --- From FlashSysInfo --- */ |
445 | uint8_t my_mac[MAC_ADDR_LEN]; | 482 | uint8_t my_mac[MAC_ADDR_LEN]; |
446 | uint8_t serial_number[16]; | 483 | uint8_t serial_number[16]; |
447 | 484 | uint16_t port_num; | |
448 | /* --- From GetFwState --- */ | 485 | /* --- From GetFwState --- */ |
449 | uint32_t firmware_state; | 486 | uint32_t firmware_state; |
450 | uint32_t addl_fw_state; | 487 | uint32_t addl_fw_state; |
@@ -569,6 +606,9 @@ struct scsi_qla_host { | |||
569 | #define CHAP_DMA_BLOCK_SIZE 512 | 606 | #define CHAP_DMA_BLOCK_SIZE 512 |
570 | struct workqueue_struct *task_wq; | 607 | struct workqueue_struct *task_wq; |
571 | unsigned long ddb_idx_map[MAX_DDB_ENTRIES / BITS_PER_LONG]; | 608 | unsigned long ddb_idx_map[MAX_DDB_ENTRIES / BITS_PER_LONG]; |
609 | #define SYSFS_FLAG_FW_SEL_BOOT 2 | ||
610 | struct iscsi_boot_kset *boot_kset; | ||
611 | struct ql4_boot_tgt_info boot_tgt; | ||
572 | }; | 612 | }; |
573 | 613 | ||
574 | struct ql4_task_data { | 614 | struct ql4_task_data { |
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h index 99098d51543b..9dc439b0d75f 100644 --- a/drivers/scsi/qla4xxx/ql4_fw.h +++ b/drivers/scsi/qla4xxx/ql4_fw.h | |||
@@ -146,6 +146,13 @@ struct isp_reg { | |||
146 | #define QL4022_NVRAM_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (10+16)) | 146 | #define QL4022_NVRAM_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (10+16)) |
147 | #define QL4022_FLASH_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (13+16)) | 147 | #define QL4022_FLASH_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (13+16)) |
148 | 148 | ||
149 | /* nvram address for 4032 */ | ||
150 | #define NVRAM_PORT0_BOOT_MODE 0x03b1 | ||
151 | #define NVRAM_PORT0_BOOT_PRI_TGT 0x03b2 | ||
152 | #define NVRAM_PORT0_BOOT_SEC_TGT 0x03bb | ||
153 | #define NVRAM_PORT1_BOOT_MODE 0x07b1 | ||
154 | #define NVRAM_PORT1_BOOT_PRI_TGT 0x07b2 | ||
155 | #define NVRAM_PORT1_BOOT_SEC_TGT 0x07bb | ||
149 | 156 | ||
150 | 157 | ||
151 | /* Page # defines for 4022 */ | 158 | /* Page # defines for 4022 */ |
@@ -298,6 +305,7 @@ struct qla_flt_header { | |||
298 | #define FLT_REG_FW_82 0x74 | 305 | #define FLT_REG_FW_82 0x74 |
299 | #define FLT_REG_GOLD_FW_82 0x75 | 306 | #define FLT_REG_GOLD_FW_82 0x75 |
300 | #define FLT_REG_BOOT_CODE_82 0x78 | 307 | #define FLT_REG_BOOT_CODE_82 0x78 |
308 | #define FLT_REG_ISCSI_PARAM 0x65 | ||
301 | 309 | ||
302 | struct qla_flt_region { | 310 | struct qla_flt_region { |
303 | uint32_t code; | 311 | uint32_t code; |
@@ -733,7 +741,10 @@ struct dev_db_entry { | |||
733 | uint8_t tcp_rcv_wsf; /* 1C7 */ | 741 | uint8_t tcp_rcv_wsf; /* 1C7 */ |
734 | uint32_t stat_sn; /* 1C8-1CB */ | 742 | uint32_t stat_sn; /* 1C8-1CB */ |
735 | uint32_t exp_stat_sn; /* 1CC-1CF */ | 743 | uint32_t exp_stat_sn; /* 1CC-1CF */ |
736 | uint8_t res6[0x30]; /* 1D0-1FF */ | 744 | uint8_t res6[0x2b]; /* 1D0-1FB */ |
745 | #define DDB_VALID_COOKIE 0x9034 | ||
746 | uint16_t cookie; /* 1FC-1FD */ | ||
747 | uint16_t len; /* 1FE-1FF */ | ||
737 | }; | 748 | }; |
738 | 749 | ||
739 | /*************************************************************************/ | 750 | /*************************************************************************/ |
@@ -745,6 +756,14 @@ struct dev_db_entry { | |||
745 | #define FLASH_EOF_OFFSET (FLASH_DEFAULTBLOCKSIZE-8) /* 4 bytes | 756 | #define FLASH_EOF_OFFSET (FLASH_DEFAULTBLOCKSIZE-8) /* 4 bytes |
746 | * for EOF | 757 | * for EOF |
747 | * signature */ | 758 | * signature */ |
759 | #define FLASH_RAW_ACCESS_ADDR 0x8e000000 | ||
760 | |||
761 | #define BOOT_PARAM_OFFSET_PORT0 0x3b0 | ||
762 | #define BOOT_PARAM_OFFSET_PORT1 0x7b0 | ||
763 | |||
764 | #define FLASH_OFFSET_DB_INFO 0x05000000 | ||
765 | #define FLASH_OFFSET_DB_END (FLASH_OFFSET_DB_INFO + 0x7fff) | ||
766 | |||
748 | 767 | ||
749 | struct sys_info_phys_addr { | 768 | struct sys_info_phys_addr { |
750 | uint8_t address[6]; /* 00-05 */ | 769 | uint8_t address[6]; /* 00-05 */ |
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index 85b8253b3fc2..98d4b17e8b10 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h | |||
@@ -60,6 +60,7 @@ int qla4xxx_get_acb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, | |||
60 | uint32_t *mbox_sts, dma_addr_t acb_dma); | 60 | uint32_t *mbox_sts, dma_addr_t acb_dma); |
61 | void qla4xxx_mark_device_missing(struct iscsi_cls_session *cls_session); | 61 | void qla4xxx_mark_device_missing(struct iscsi_cls_session *cls_session); |
62 | u16 rd_nvram_word(struct scsi_qla_host *ha, int offset); | 62 | u16 rd_nvram_word(struct scsi_qla_host *ha, int offset); |
63 | u8 rd_nvram_byte(struct scsi_qla_host *ha, int offset); | ||
63 | void qla4xxx_get_crash_record(struct scsi_qla_host *ha); | 64 | void qla4xxx_get_crash_record(struct scsi_qla_host *ha); |
64 | int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host *ha); | 65 | int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host *ha); |
65 | int qla4xxx_about_firmware(struct scsi_qla_host *ha); | 66 | 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, | |||
154 | uint16_t stats_size, dma_addr_t stats_dma); | 155 | uint16_t stats_size, dma_addr_t stats_dma); |
155 | void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, | 156 | void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, |
156 | struct ddb_entry *ddb_entry); | 157 | struct ddb_entry *ddb_entry); |
158 | int qla4xxx_bootdb_by_index(struct scsi_qla_host *ha, | ||
159 | struct dev_db_entry *fw_ddb_entry, | ||
160 | dma_addr_t fw_ddb_entry_dma, uint16_t ddb_index); | ||
161 | int qla4xxx_get_chap(struct scsi_qla_host *ha, char *username, | ||
162 | char *password, uint16_t idx); | ||
163 | |||
157 | /* BSG Functions */ | 164 | /* BSG Functions */ |
158 | int qla4xxx_bsg_request(struct bsg_job *bsg_job); | 165 | int qla4xxx_bsg_request(struct bsg_job *bsg_job); |
159 | int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job); | 166 | int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job); |
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index 21884019dab8..72ec7e092296 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c | |||
@@ -1262,6 +1262,83 @@ int qla4xxx_set_flash(struct scsi_qla_host *ha, dma_addr_t dma_addr, | |||
1262 | return status; | 1262 | return status; |
1263 | } | 1263 | } |
1264 | 1264 | ||
1265 | int qla4xxx_bootdb_by_index(struct scsi_qla_host *ha, | ||
1266 | struct dev_db_entry *fw_ddb_entry, | ||
1267 | dma_addr_t fw_ddb_entry_dma, uint16_t ddb_index) | ||
1268 | { | ||
1269 | uint32_t dev_db_start_offset = FLASH_OFFSET_DB_INFO; | ||
1270 | uint32_t dev_db_end_offset; | ||
1271 | int status = QLA_ERROR; | ||
1272 | |||
1273 | memset(fw_ddb_entry, 0, sizeof(*fw_ddb_entry)); | ||
1274 | |||
1275 | dev_db_start_offset += (ddb_index * sizeof(*fw_ddb_entry)); | ||
1276 | dev_db_end_offset = FLASH_OFFSET_DB_END; | ||
1277 | |||
1278 | if (dev_db_start_offset > dev_db_end_offset) { | ||
1279 | DEBUG2(ql4_printk(KERN_ERR, ha, | ||
1280 | "%s:Invalid DDB index %d", __func__, | ||
1281 | ddb_index)); | ||
1282 | goto exit_bootdb_failed; | ||
1283 | } | ||
1284 | |||
1285 | if (qla4xxx_get_flash(ha, fw_ddb_entry_dma, dev_db_start_offset, | ||
1286 | sizeof(*fw_ddb_entry)) != QLA_SUCCESS) { | ||
1287 | ql4_printk(KERN_ERR, ha, "scsi%ld: %s: Get Flash" | ||
1288 | "failed\n", ha->host_no, __func__); | ||
1289 | goto exit_bootdb_failed; | ||
1290 | } | ||
1291 | |||
1292 | if (fw_ddb_entry->cookie == DDB_VALID_COOKIE) | ||
1293 | status = QLA_SUCCESS; | ||
1294 | |||
1295 | exit_bootdb_failed: | ||
1296 | return status; | ||
1297 | } | ||
1298 | |||
1299 | int qla4xxx_get_chap(struct scsi_qla_host *ha, char *username, char *password, | ||
1300 | uint16_t idx) | ||
1301 | { | ||
1302 | int ret = 0; | ||
1303 | int rval = QLA_ERROR; | ||
1304 | uint32_t offset = 0; | ||
1305 | struct ql4_chap_table *chap_table; | ||
1306 | dma_addr_t chap_dma; | ||
1307 | |||
1308 | chap_table = dma_pool_alloc(ha->chap_dma_pool, GFP_KERNEL, &chap_dma); | ||
1309 | if (chap_table == NULL) { | ||
1310 | ret = -ENOMEM; | ||
1311 | goto exit_get_chap; | ||
1312 | } | ||
1313 | |||
1314 | memset(chap_table, 0, sizeof(struct ql4_chap_table)); | ||
1315 | |||
1316 | offset = 0x06000000 | (idx * sizeof(struct ql4_chap_table)); | ||
1317 | |||
1318 | rval = qla4xxx_get_flash(ha, chap_dma, offset, | ||
1319 | sizeof(struct ql4_chap_table)); | ||
1320 | if (rval != QLA_SUCCESS) { | ||
1321 | ret = -EINVAL; | ||
1322 | goto exit_get_chap; | ||
1323 | } | ||
1324 | |||
1325 | DEBUG2(ql4_printk(KERN_INFO, ha, "Chap Cookie: x%x\n", | ||
1326 | __le16_to_cpu(chap_table->cookie))); | ||
1327 | |||
1328 | if (__le16_to_cpu(chap_table->cookie) != CHAP_VALID_COOKIE) { | ||
1329 | ql4_printk(KERN_ERR, ha, "No valid chap entry found\n"); | ||
1330 | goto exit_get_chap; | ||
1331 | } | ||
1332 | |||
1333 | strncpy(password, chap_table->secret, QL4_CHAP_MAX_SECRET_LEN); | ||
1334 | strncpy(username, chap_table->name, QL4_CHAP_MAX_NAME_LEN); | ||
1335 | chap_table->cookie = __constant_cpu_to_le16(CHAP_VALID_COOKIE); | ||
1336 | |||
1337 | exit_get_chap: | ||
1338 | dma_pool_free(ha->chap_dma_pool, chap_table, chap_dma); | ||
1339 | return ret; | ||
1340 | } | ||
1341 | |||
1265 | static int qla4xxx_set_chap(struct scsi_qla_host *ha, char *username, | 1342 | static int qla4xxx_set_chap(struct scsi_qla_host *ha, char *username, |
1266 | char *password, uint16_t idx, int bidi) | 1343 | char *password, uint16_t idx, int bidi) |
1267 | { | 1344 | { |
diff --git a/drivers/scsi/qla4xxx/ql4_nvram.c b/drivers/scsi/qla4xxx/ql4_nvram.c index b4b859b2d47e..7851f314ba96 100644 --- a/drivers/scsi/qla4xxx/ql4_nvram.c +++ b/drivers/scsi/qla4xxx/ql4_nvram.c | |||
@@ -156,6 +156,27 @@ u16 rd_nvram_word(struct scsi_qla_host * ha, int offset) | |||
156 | return val; | 156 | return val; |
157 | } | 157 | } |
158 | 158 | ||
159 | u8 rd_nvram_byte(struct scsi_qla_host *ha, int offset) | ||
160 | { | ||
161 | u16 val = 0; | ||
162 | u8 rval = 0; | ||
163 | int index = 0; | ||
164 | |||
165 | if (offset & 0x1) | ||
166 | index = (offset - 1) / 2; | ||
167 | else | ||
168 | index = offset / 2; | ||
169 | |||
170 | val = le16_to_cpu(rd_nvram_word(ha, index)); | ||
171 | |||
172 | if (offset & 0x1) | ||
173 | rval = (u8)((val & 0xff00) >> 8); | ||
174 | else | ||
175 | rval = (u8)((val & 0x00ff)); | ||
176 | |||
177 | return rval; | ||
178 | } | ||
179 | |||
159 | int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host * ha) | 180 | int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host * ha) |
160 | { | 181 | { |
161 | int status = QLA_ERROR; | 182 | int status = QLA_ERROR; |
diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c index fdfe27b38698..52a1063e4fd5 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.c +++ b/drivers/scsi/qla4xxx/ql4_nx.c | |||
@@ -2020,6 +2020,9 @@ qla4_8xxx_get_flt_info(struct scsi_qla_host *ha, uint32_t flt_addr) | |||
2020 | case FLT_REG_BOOTLOAD_82: | 2020 | case FLT_REG_BOOTLOAD_82: |
2021 | hw->flt_region_bootload = start; | 2021 | hw->flt_region_bootload = start; |
2022 | break; | 2022 | break; |
2023 | case FLT_REG_ISCSI_PARAM: | ||
2024 | hw->flt_iscsi_param = start; | ||
2025 | break; | ||
2023 | } | 2026 | } |
2024 | } | 2027 | } |
2025 | goto done; | 2028 | goto done; |
@@ -2258,6 +2261,7 @@ int qla4_8xxx_get_sys_info(struct scsi_qla_host *ha) | |||
2258 | } | 2261 | } |
2259 | 2262 | ||
2260 | /* Save M.A.C. address & serial_number */ | 2263 | /* Save M.A.C. address & serial_number */ |
2264 | ha->port_num = sys_info->port_num; | ||
2261 | memcpy(ha->my_mac, &sys_info->mac_addr[0], | 2265 | memcpy(ha->my_mac, &sys_info->mac_addr[0], |
2262 | min(sizeof(ha->my_mac), sizeof(sys_info->mac_addr))); | 2266 | min(sizeof(ha->my_mac), sizeof(sys_info->mac_addr))); |
2263 | memcpy(ha->serial_number, &sys_info->serial_number, | 2267 | memcpy(ha->serial_number, &sys_info->serial_number, |
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index bfb3d37612fc..15355f95f560 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c | |||
@@ -6,6 +6,8 @@ | |||
6 | */ | 6 | */ |
7 | #include <linux/moduleparam.h> | 7 | #include <linux/moduleparam.h> |
8 | #include <linux/slab.h> | 8 | #include <linux/slab.h> |
9 | #include <linux/blkdev.h> | ||
10 | #include <linux/iscsi_boot_sysfs.h> | ||
9 | 11 | ||
10 | #include <scsi/scsi_tcq.h> | 12 | #include <scsi/scsi_tcq.h> |
11 | #include <scsi/scsicam.h> | 13 | #include <scsi/scsicam.h> |
@@ -2551,6 +2553,477 @@ uint16_t qla4_8xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) | |||
2551 | return (uint16_t)le32_to_cpu(readl(&ha->qla4_8xxx_reg->rsp_q_in)); | 2553 | return (uint16_t)le32_to_cpu(readl(&ha->qla4_8xxx_reg->rsp_q_in)); |
2552 | } | 2554 | } |
2553 | 2555 | ||
2556 | static ssize_t qla4xxx_show_boot_eth_info(void *data, int type, char *buf) | ||
2557 | { | ||
2558 | struct scsi_qla_host *ha = data; | ||
2559 | char *str = buf; | ||
2560 | int rc; | ||
2561 | |||
2562 | switch (type) { | ||
2563 | case ISCSI_BOOT_ETH_FLAGS: | ||
2564 | rc = sprintf(str, "%d\n", SYSFS_FLAG_FW_SEL_BOOT); | ||
2565 | break; | ||
2566 | case ISCSI_BOOT_ETH_INDEX: | ||
2567 | rc = sprintf(str, "0\n"); | ||
2568 | break; | ||
2569 | case ISCSI_BOOT_ETH_MAC: | ||
2570 | rc = sysfs_format_mac(str, ha->my_mac, | ||
2571 | MAC_ADDR_LEN); | ||
2572 | break; | ||
2573 | default: | ||
2574 | rc = -ENOSYS; | ||
2575 | break; | ||
2576 | } | ||
2577 | return rc; | ||
2578 | } | ||
2579 | |||
2580 | static mode_t qla4xxx_eth_get_attr_visibility(void *data, int type) | ||
2581 | { | ||
2582 | int rc; | ||
2583 | |||
2584 | switch (type) { | ||
2585 | case ISCSI_BOOT_ETH_FLAGS: | ||
2586 | case ISCSI_BOOT_ETH_MAC: | ||
2587 | case ISCSI_BOOT_ETH_INDEX: | ||
2588 | rc = S_IRUGO; | ||
2589 | break; | ||
2590 | default: | ||
2591 | rc = 0; | ||
2592 | break; | ||
2593 | } | ||
2594 | return rc; | ||
2595 | } | ||
2596 | |||
2597 | static ssize_t qla4xxx_show_boot_ini_info(void *data, int type, char *buf) | ||
2598 | { | ||
2599 | struct scsi_qla_host *ha = data; | ||
2600 | char *str = buf; | ||
2601 | int rc; | ||
2602 | |||
2603 | switch (type) { | ||
2604 | case ISCSI_BOOT_INI_INITIATOR_NAME: | ||
2605 | rc = sprintf(str, "%s\n", ha->name_string); | ||
2606 | break; | ||
2607 | default: | ||
2608 | rc = -ENOSYS; | ||
2609 | break; | ||
2610 | } | ||
2611 | return rc; | ||
2612 | } | ||
2613 | |||
2614 | static mode_t qla4xxx_ini_get_attr_visibility(void *data, int type) | ||
2615 | { | ||
2616 | int rc; | ||
2617 | |||
2618 | switch (type) { | ||
2619 | case ISCSI_BOOT_INI_INITIATOR_NAME: | ||
2620 | rc = S_IRUGO; | ||
2621 | break; | ||
2622 | default: | ||
2623 | rc = 0; | ||
2624 | break; | ||
2625 | } | ||
2626 | return rc; | ||
2627 | } | ||
2628 | |||
2629 | static ssize_t | ||
2630 | qla4xxx_show_boot_tgt_info(struct ql4_boot_session_info *boot_sess, int type, | ||
2631 | char *buf) | ||
2632 | { | ||
2633 | struct ql4_conn_info *boot_conn = &boot_sess->conn_list[0]; | ||
2634 | char *str = buf; | ||
2635 | int rc; | ||
2636 | |||
2637 | switch (type) { | ||
2638 | case ISCSI_BOOT_TGT_NAME: | ||
2639 | rc = sprintf(buf, "%s\n", (char *)&boot_sess->target_name); | ||
2640 | break; | ||
2641 | case ISCSI_BOOT_TGT_IP_ADDR: | ||
2642 | if (boot_sess->conn_list[0].dest_ipaddr.ip_type == 0x1) | ||
2643 | rc = sprintf(buf, "%pI4\n", | ||
2644 | &boot_conn->dest_ipaddr.ip_address); | ||
2645 | else | ||
2646 | rc = sprintf(str, "%pI6\n", | ||
2647 | &boot_conn->dest_ipaddr.ip_address); | ||
2648 | break; | ||
2649 | case ISCSI_BOOT_TGT_PORT: | ||
2650 | rc = sprintf(str, "%d\n", boot_conn->dest_port); | ||
2651 | break; | ||
2652 | case ISCSI_BOOT_TGT_CHAP_NAME: | ||
2653 | rc = sprintf(str, "%.*s\n", | ||
2654 | boot_conn->chap.target_chap_name_length, | ||
2655 | (char *)&boot_conn->chap.target_chap_name); | ||
2656 | break; | ||
2657 | case ISCSI_BOOT_TGT_CHAP_SECRET: | ||
2658 | rc = sprintf(str, "%.*s\n", | ||
2659 | boot_conn->chap.target_secret_length, | ||
2660 | (char *)&boot_conn->chap.target_secret); | ||
2661 | break; | ||
2662 | case ISCSI_BOOT_TGT_REV_CHAP_NAME: | ||
2663 | rc = sprintf(str, "%.*s\n", | ||
2664 | boot_conn->chap.intr_chap_name_length, | ||
2665 | (char *)&boot_conn->chap.intr_chap_name); | ||
2666 | break; | ||
2667 | case ISCSI_BOOT_TGT_REV_CHAP_SECRET: | ||
2668 | rc = sprintf(str, "%.*s\n", | ||
2669 | boot_conn->chap.intr_secret_length, | ||
2670 | (char *)&boot_conn->chap.intr_secret); | ||
2671 | break; | ||
2672 | case ISCSI_BOOT_TGT_FLAGS: | ||
2673 | rc = sprintf(str, "%d\n", SYSFS_FLAG_FW_SEL_BOOT); | ||
2674 | break; | ||
2675 | case ISCSI_BOOT_TGT_NIC_ASSOC: | ||
2676 | rc = sprintf(str, "0\n"); | ||
2677 | break; | ||
2678 | default: | ||
2679 | rc = -ENOSYS; | ||
2680 | break; | ||
2681 | } | ||
2682 | return rc; | ||
2683 | } | ||
2684 | |||
2685 | static ssize_t qla4xxx_show_boot_tgt_pri_info(void *data, int type, char *buf) | ||
2686 | { | ||
2687 | struct scsi_qla_host *ha = data; | ||
2688 | struct ql4_boot_session_info *boot_sess = &(ha->boot_tgt.boot_pri_sess); | ||
2689 | |||
2690 | return qla4xxx_show_boot_tgt_info(boot_sess, type, buf); | ||
2691 | } | ||
2692 | |||
2693 | static ssize_t qla4xxx_show_boot_tgt_sec_info(void *data, int type, char *buf) | ||
2694 | { | ||
2695 | struct scsi_qla_host *ha = data; | ||
2696 | struct ql4_boot_session_info *boot_sess = &(ha->boot_tgt.boot_sec_sess); | ||
2697 | |||
2698 | return qla4xxx_show_boot_tgt_info(boot_sess, type, buf); | ||
2699 | } | ||
2700 | |||
2701 | static mode_t qla4xxx_tgt_get_attr_visibility(void *data, int type) | ||
2702 | { | ||
2703 | int rc; | ||
2704 | |||
2705 | switch (type) { | ||
2706 | case ISCSI_BOOT_TGT_NAME: | ||
2707 | case ISCSI_BOOT_TGT_IP_ADDR: | ||
2708 | case ISCSI_BOOT_TGT_PORT: | ||
2709 | case ISCSI_BOOT_TGT_CHAP_NAME: | ||
2710 | case ISCSI_BOOT_TGT_CHAP_SECRET: | ||
2711 | case ISCSI_BOOT_TGT_REV_CHAP_NAME: | ||
2712 | case ISCSI_BOOT_TGT_REV_CHAP_SECRET: | ||
2713 | case ISCSI_BOOT_TGT_NIC_ASSOC: | ||
2714 | case ISCSI_BOOT_TGT_FLAGS: | ||
2715 | rc = S_IRUGO; | ||
2716 | break; | ||
2717 | default: | ||
2718 | rc = 0; | ||
2719 | break; | ||
2720 | } | ||
2721 | return rc; | ||
2722 | } | ||
2723 | |||
2724 | static void qla4xxx_boot_release(void *data) | ||
2725 | { | ||
2726 | struct scsi_qla_host *ha = data; | ||
2727 | |||
2728 | scsi_host_put(ha->host); | ||
2729 | } | ||
2730 | |||
2731 | static int get_fw_boot_info(struct scsi_qla_host *ha, uint16_t ddb_index[]) | ||
2732 | { | ||
2733 | dma_addr_t buf_dma; | ||
2734 | uint32_t addr, pri_addr, sec_addr; | ||
2735 | uint32_t offset; | ||
2736 | uint16_t func_num; | ||
2737 | uint8_t val; | ||
2738 | uint8_t *buf = NULL; | ||
2739 | size_t size = 13 * sizeof(uint8_t); | ||
2740 | int ret = QLA_SUCCESS; | ||
2741 | |||
2742 | func_num = PCI_FUNC(ha->pdev->devfn); | ||
2743 | |||
2744 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
2745 | "%s: Get FW boot info for 0x%x func %d\n", __func__, | ||
2746 | (is_qla4032(ha) ? PCI_DEVICE_ID_QLOGIC_ISP4032 : | ||
2747 | PCI_DEVICE_ID_QLOGIC_ISP8022), func_num)); | ||
2748 | |||
2749 | if (is_qla4032(ha)) { | ||
2750 | if (func_num == 1) { | ||
2751 | addr = NVRAM_PORT0_BOOT_MODE; | ||
2752 | pri_addr = NVRAM_PORT0_BOOT_PRI_TGT; | ||
2753 | sec_addr = NVRAM_PORT0_BOOT_SEC_TGT; | ||
2754 | } else if (func_num == 3) { | ||
2755 | addr = NVRAM_PORT1_BOOT_MODE; | ||
2756 | pri_addr = NVRAM_PORT1_BOOT_PRI_TGT; | ||
2757 | sec_addr = NVRAM_PORT1_BOOT_SEC_TGT; | ||
2758 | } else { | ||
2759 | ret = QLA_ERROR; | ||
2760 | goto exit_boot_info; | ||
2761 | } | ||
2762 | |||
2763 | /* Check Boot Mode */ | ||
2764 | val = rd_nvram_byte(ha, addr); | ||
2765 | if (!(val & 0x07)) { | ||
2766 | DEBUG2(ql4_printk(KERN_ERR, ha, | ||
2767 | "%s: Failed Boot options : 0x%x\n", | ||
2768 | __func__, val)); | ||
2769 | ret = QLA_ERROR; | ||
2770 | goto exit_boot_info; | ||
2771 | } | ||
2772 | |||
2773 | /* get primary valid target index */ | ||
2774 | val = rd_nvram_byte(ha, pri_addr); | ||
2775 | if (val & BIT_7) | ||
2776 | ddb_index[0] = (val & 0x7f); | ||
2777 | else | ||
2778 | ddb_index[0] = 0; | ||
2779 | |||
2780 | /* get secondary valid target index */ | ||
2781 | val = rd_nvram_byte(ha, sec_addr); | ||
2782 | if (val & BIT_7) | ||
2783 | ddb_index[1] = (val & 0x7f); | ||
2784 | else | ||
2785 | ddb_index[1] = 1; | ||
2786 | |||
2787 | } else if (is_qla8022(ha)) { | ||
2788 | buf = dma_alloc_coherent(&ha->pdev->dev, size, | ||
2789 | &buf_dma, GFP_KERNEL); | ||
2790 | if (!buf) { | ||
2791 | DEBUG2(ql4_printk(KERN_ERR, ha, | ||
2792 | "%s: Unable to allocate dma buffer\n", | ||
2793 | __func__)); | ||
2794 | ret = QLA_ERROR; | ||
2795 | goto exit_boot_info; | ||
2796 | } | ||
2797 | |||
2798 | if (ha->port_num == 0) | ||
2799 | offset = BOOT_PARAM_OFFSET_PORT0; | ||
2800 | else if (ha->port_num == 1) | ||
2801 | offset = BOOT_PARAM_OFFSET_PORT1; | ||
2802 | else { | ||
2803 | ret = QLA_ERROR; | ||
2804 | goto exit_boot_info_free; | ||
2805 | } | ||
2806 | addr = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_iscsi_param * 4) + | ||
2807 | offset; | ||
2808 | if (qla4xxx_get_flash(ha, buf_dma, addr, | ||
2809 | 13 * sizeof(uint8_t)) != QLA_SUCCESS) { | ||
2810 | DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: Get Flash" | ||
2811 | "failed\n", ha->host_no, __func__)); | ||
2812 | ret = QLA_ERROR; | ||
2813 | goto exit_boot_info_free; | ||
2814 | } | ||
2815 | /* Check Boot Mode */ | ||
2816 | if (!(buf[1] & 0x07)) { | ||
2817 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
2818 | "Failed: Boot options : 0x%x\n", | ||
2819 | buf[1])); | ||
2820 | ret = QLA_ERROR; | ||
2821 | goto exit_boot_info_free; | ||
2822 | } | ||
2823 | |||
2824 | /* get primary valid target index */ | ||
2825 | if (buf[2] & BIT_7) | ||
2826 | ddb_index[0] = buf[2] & 0x7f; | ||
2827 | else | ||
2828 | ddb_index[0] = 0; | ||
2829 | |||
2830 | /* get secondary valid target index */ | ||
2831 | if (buf[11] & BIT_7) | ||
2832 | ddb_index[1] = buf[11] & 0x7f; | ||
2833 | else | ||
2834 | ddb_index[1] = 1; | ||
2835 | |||
2836 | } else { | ||
2837 | ret = QLA_ERROR; | ||
2838 | goto exit_boot_info; | ||
2839 | } | ||
2840 | |||
2841 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Primary target ID %d, Secondary" | ||
2842 | " target ID %d\n", __func__, ddb_index[0], | ||
2843 | ddb_index[1])); | ||
2844 | |||
2845 | exit_boot_info_free: | ||
2846 | dma_free_coherent(&ha->pdev->dev, size, buf, buf_dma); | ||
2847 | exit_boot_info: | ||
2848 | return ret; | ||
2849 | } | ||
2850 | |||
2851 | static int qla4xxx_get_boot_target(struct scsi_qla_host *ha, | ||
2852 | struct ql4_boot_session_info *boot_sess, | ||
2853 | uint16_t ddb_index) | ||
2854 | { | ||
2855 | struct ql4_conn_info *boot_conn = &boot_sess->conn_list[0]; | ||
2856 | struct dev_db_entry *fw_ddb_entry; | ||
2857 | dma_addr_t fw_ddb_entry_dma; | ||
2858 | uint16_t idx; | ||
2859 | uint16_t options; | ||
2860 | int ret = QLA_SUCCESS; | ||
2861 | |||
2862 | fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), | ||
2863 | &fw_ddb_entry_dma, GFP_KERNEL); | ||
2864 | if (!fw_ddb_entry) { | ||
2865 | DEBUG2(ql4_printk(KERN_ERR, ha, | ||
2866 | "%s: Unable to allocate dma buffer.\n", | ||
2867 | __func__)); | ||
2868 | ret = QLA_ERROR; | ||
2869 | return ret; | ||
2870 | } | ||
2871 | |||
2872 | if (qla4xxx_bootdb_by_index(ha, fw_ddb_entry, | ||
2873 | fw_ddb_entry_dma, ddb_index)) { | ||
2874 | DEBUG2(ql4_printk(KERN_ERR, ha, | ||
2875 | "%s: Flash DDB read Failed\n", __func__)); | ||
2876 | ret = QLA_ERROR; | ||
2877 | goto exit_boot_target; | ||
2878 | } | ||
2879 | |||
2880 | /* Update target name and IP from DDB */ | ||
2881 | memcpy(boot_sess->target_name, fw_ddb_entry->iscsi_name, | ||
2882 | min(sizeof(boot_sess->target_name), | ||
2883 | sizeof(fw_ddb_entry->iscsi_name))); | ||
2884 | |||
2885 | options = le16_to_cpu(fw_ddb_entry->options); | ||
2886 | if (options & DDB_OPT_IPV6_DEVICE) { | ||
2887 | memcpy(&boot_conn->dest_ipaddr.ip_address, | ||
2888 | &fw_ddb_entry->ip_addr[0], IPv6_ADDR_LEN); | ||
2889 | } else { | ||
2890 | boot_conn->dest_ipaddr.ip_type = 0x1; | ||
2891 | memcpy(&boot_conn->dest_ipaddr.ip_address, | ||
2892 | &fw_ddb_entry->ip_addr[0], IP_ADDR_LEN); | ||
2893 | } | ||
2894 | |||
2895 | boot_conn->dest_port = le16_to_cpu(fw_ddb_entry->port); | ||
2896 | |||
2897 | /* update chap information */ | ||
2898 | idx = __le16_to_cpu(fw_ddb_entry->chap_tbl_idx); | ||
2899 | |||
2900 | if (BIT_7 & le16_to_cpu(fw_ddb_entry->iscsi_options)) { | ||
2901 | |||
2902 | DEBUG2(ql4_printk(KERN_INFO, ha, "Setting chap\n")); | ||
2903 | |||
2904 | ret = qla4xxx_get_chap(ha, (char *)&boot_conn->chap. | ||
2905 | target_chap_name, | ||
2906 | (char *)&boot_conn->chap.target_secret, | ||
2907 | idx); | ||
2908 | if (ret) { | ||
2909 | ql4_printk(KERN_ERR, ha, "Failed to set chap\n"); | ||
2910 | ret = QLA_ERROR; | ||
2911 | goto exit_boot_target; | ||
2912 | } | ||
2913 | |||
2914 | boot_conn->chap.target_chap_name_length = QL4_CHAP_MAX_NAME_LEN; | ||
2915 | boot_conn->chap.target_secret_length = QL4_CHAP_MAX_SECRET_LEN; | ||
2916 | } | ||
2917 | |||
2918 | if (BIT_4 & le16_to_cpu(fw_ddb_entry->iscsi_options)) { | ||
2919 | |||
2920 | DEBUG2(ql4_printk(KERN_INFO, ha, "Setting BIDI chap\n")); | ||
2921 | |||
2922 | ret = qla4xxx_get_chap(ha, (char *)&boot_conn->chap. | ||
2923 | intr_chap_name, | ||
2924 | (char *)&boot_conn->chap.intr_secret, | ||
2925 | (idx + 1)); | ||
2926 | if (ret) { | ||
2927 | ql4_printk(KERN_ERR, ha, "Failed to set BIDI chap\n"); | ||
2928 | ret = QLA_ERROR; | ||
2929 | goto exit_boot_target; | ||
2930 | } | ||
2931 | |||
2932 | boot_conn->chap.intr_chap_name_length = QL4_CHAP_MAX_NAME_LEN; | ||
2933 | boot_conn->chap.intr_secret_length = QL4_CHAP_MAX_SECRET_LEN; | ||
2934 | } | ||
2935 | |||
2936 | exit_boot_target: | ||
2937 | dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), | ||
2938 | fw_ddb_entry, fw_ddb_entry_dma); | ||
2939 | return ret; | ||
2940 | } | ||
2941 | |||
2942 | static int qla4xxx_get_boot_info(struct scsi_qla_host *ha) | ||
2943 | { | ||
2944 | uint16_t ddb_index[2]; | ||
2945 | int ret = QLA_SUCCESS; | ||
2946 | |||
2947 | memset(ddb_index, 0, sizeof(ddb_index)); | ||
2948 | ret = get_fw_boot_info(ha, ddb_index); | ||
2949 | if (ret != QLA_SUCCESS) { | ||
2950 | DEBUG2(ql4_printk(KERN_ERR, ha, | ||
2951 | "%s: Failed to set boot info.\n", __func__)); | ||
2952 | return ret; | ||
2953 | } | ||
2954 | |||
2955 | ret = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_pri_sess), | ||
2956 | ddb_index[0]); | ||
2957 | if (ret != QLA_SUCCESS) { | ||
2958 | DEBUG2(ql4_printk(KERN_ERR, ha, "%s: Failed to get " | ||
2959 | "primary target\n", __func__)); | ||
2960 | } | ||
2961 | |||
2962 | ret = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_sec_sess), | ||
2963 | ddb_index[1]); | ||
2964 | if (ret != QLA_SUCCESS) { | ||
2965 | DEBUG2(ql4_printk(KERN_ERR, ha, "%s: Failed to get " | ||
2966 | "secondary target\n", __func__)); | ||
2967 | } | ||
2968 | return ret; | ||
2969 | } | ||
2970 | |||
2971 | static int qla4xxx_setup_boot_info(struct scsi_qla_host *ha) | ||
2972 | { | ||
2973 | struct iscsi_boot_kobj *boot_kobj; | ||
2974 | |||
2975 | if (qla4xxx_get_boot_info(ha) != QLA_SUCCESS) | ||
2976 | return 0; | ||
2977 | |||
2978 | ha->boot_kset = iscsi_boot_create_host_kset(ha->host->host_no); | ||
2979 | if (!ha->boot_kset) | ||
2980 | goto kset_free; | ||
2981 | |||
2982 | if (!scsi_host_get(ha->host)) | ||
2983 | goto kset_free; | ||
2984 | boot_kobj = iscsi_boot_create_target(ha->boot_kset, 0, ha, | ||
2985 | qla4xxx_show_boot_tgt_pri_info, | ||
2986 | qla4xxx_tgt_get_attr_visibility, | ||
2987 | qla4xxx_boot_release); | ||
2988 | if (!boot_kobj) | ||
2989 | goto put_host; | ||
2990 | |||
2991 | if (!scsi_host_get(ha->host)) | ||
2992 | goto kset_free; | ||
2993 | boot_kobj = iscsi_boot_create_target(ha->boot_kset, 1, ha, | ||
2994 | qla4xxx_show_boot_tgt_sec_info, | ||
2995 | qla4xxx_tgt_get_attr_visibility, | ||
2996 | qla4xxx_boot_release); | ||
2997 | if (!boot_kobj) | ||
2998 | goto put_host; | ||
2999 | |||
3000 | if (!scsi_host_get(ha->host)) | ||
3001 | goto kset_free; | ||
3002 | boot_kobj = iscsi_boot_create_initiator(ha->boot_kset, 0, ha, | ||
3003 | qla4xxx_show_boot_ini_info, | ||
3004 | qla4xxx_ini_get_attr_visibility, | ||
3005 | qla4xxx_boot_release); | ||
3006 | if (!boot_kobj) | ||
3007 | goto put_host; | ||
3008 | |||
3009 | if (!scsi_host_get(ha->host)) | ||
3010 | goto kset_free; | ||
3011 | boot_kobj = iscsi_boot_create_ethernet(ha->boot_kset, 0, ha, | ||
3012 | qla4xxx_show_boot_eth_info, | ||
3013 | qla4xxx_eth_get_attr_visibility, | ||
3014 | qla4xxx_boot_release); | ||
3015 | if (!boot_kobj) | ||
3016 | goto put_host; | ||
3017 | |||
3018 | return 0; | ||
3019 | |||
3020 | put_host: | ||
3021 | scsi_host_put(ha->host); | ||
3022 | kset_free: | ||
3023 | iscsi_boot_destroy_kset(ha->boot_kset); | ||
3024 | return -ENOMEM; | ||
3025 | } | ||
3026 | |||
2554 | /** | 3027 | /** |
2555 | * qla4xxx_probe_adapter - callback function to probe HBA | 3028 | * qla4xxx_probe_adapter - callback function to probe HBA |
2556 | * @pdev: pointer to pci_dev structure | 3029 | * @pdev: pointer to pci_dev structure |
@@ -2758,6 +3231,10 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, | |||
2758 | ha->host_no, ha->firmware_version[0], ha->firmware_version[1], | 3231 | ha->host_no, ha->firmware_version[0], ha->firmware_version[1], |
2759 | ha->patch_number, ha->build_number); | 3232 | ha->patch_number, ha->build_number); |
2760 | 3233 | ||
3234 | if (qla4xxx_setup_boot_info(ha)) | ||
3235 | ql4_printk(KERN_ERR, ha, "%s:ISCSI boot info setup failed\n", | ||
3236 | __func__); | ||
3237 | |||
2761 | qla4xxx_create_ifaces(ha); | 3238 | qla4xxx_create_ifaces(ha); |
2762 | return 0; | 3239 | return 0; |
2763 | 3240 | ||
@@ -2831,6 +3308,9 @@ static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev) | |||
2831 | /* destroy iface from sysfs */ | 3308 | /* destroy iface from sysfs */ |
2832 | qla4xxx_destroy_ifaces(ha); | 3309 | qla4xxx_destroy_ifaces(ha); |
2833 | 3310 | ||
3311 | if (ha->boot_kset) | ||
3312 | iscsi_boot_destroy_kset(ha->boot_kset); | ||
3313 | |||
2834 | scsi_remove_host(ha->host); | 3314 | scsi_remove_host(ha->host); |
2835 | 3315 | ||
2836 | qla4xxx_free_adapter(ha); | 3316 | qla4xxx_free_adapter(ha); |