diff options
author | Joe Carnuccio <joe.carnuccio@qlogic.com> | 2009-03-24 12:08:06 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-04-03 10:22:48 -0400 |
commit | 1d2874de809a14e6780246b99a18bbc0fc0a8f2a (patch) | |
tree | 0f9dc305dc6f802c27bcef6edc607832864b7687 /drivers/scsi | |
parent | b9978769877c6c90c8d6777df13b9ae427af40b7 (diff) |
[SCSI] qla2xxx: Add Flash-Access-Control support for recent ISPs.
Given the low-level interface varies from one flash-part
manufacturer to the next, the Flash-Access-Control (FAC) mailbox
command makes the specific flash type transparent to the driver
by encapsulating a basic set of accessor and update routines.
Use these new routines where applicable by querying FAC opcode
get-sector-size at init-time.
Additional cleanups and
Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_def.h | 3 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_fw.h | 14 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gbl.h | 9 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_init.c | 15 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_mbx.c | 97 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_sup.c | 60 |
6 files changed, 184 insertions, 14 deletions
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 261c869dda22..bca572f93bcc 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h | |||
@@ -2260,7 +2260,7 @@ struct qla_hw_data { | |||
2260 | uint32_t vsan_enabled :1; | 2260 | uint32_t vsan_enabled :1; |
2261 | uint32_t npiv_supported :1; | 2261 | uint32_t npiv_supported :1; |
2262 | uint32_t fce_enabled :1; | 2262 | uint32_t fce_enabled :1; |
2263 | uint32_t hw_event_marker_found:1; | 2263 | uint32_t fac_supported :1; |
2264 | } flags; | 2264 | } flags; |
2265 | 2265 | ||
2266 | /* This spinlock is used to protect "io transactions", you must | 2266 | /* This spinlock is used to protect "io transactions", you must |
@@ -2382,6 +2382,7 @@ struct qla_hw_data { | |||
2382 | IS_QLA25XX(ha) || IS_QLA81XX(ha)) | 2382 | IS_QLA25XX(ha) || IS_QLA81XX(ha)) |
2383 | #define IS_NOPOLLING_TYPE(ha) ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && \ | 2383 | #define IS_NOPOLLING_TYPE(ha) ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && \ |
2384 | (ha)->flags.msix_enabled) | 2384 | (ha)->flags.msix_enabled) |
2385 | #define IS_FAC_REQUIRED(ha) (IS_QLA81XX(ha)) | ||
2385 | 2386 | ||
2386 | #define IS_IIDMA_CAPABLE(ha) ((ha)->device_type & DT_IIDMA) | 2387 | #define IS_IIDMA_CAPABLE(ha) ((ha)->device_type & DT_IIDMA) |
2387 | #define IS_FWI2_CAPABLE(ha) ((ha)->device_type & DT_FWI2) | 2388 | #define IS_FWI2_CAPABLE(ha) ((ha)->device_type & DT_FWI2) |
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 05cf8380a486..98301931772a 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h | |||
@@ -1403,6 +1403,20 @@ struct access_chip_rsp_84xx { | |||
1403 | #define MBA_IDC_TIME_EXT 0x8102 | 1403 | #define MBA_IDC_TIME_EXT 0x8102 |
1404 | 1404 | ||
1405 | #define MBC_IDC_ACK 0x101 | 1405 | #define MBC_IDC_ACK 0x101 |
1406 | #define MBC_FLASH_ACCESS_CTRL 0x3e /* Control flash access. */ | ||
1407 | |||
1408 | /* Flash access control option field bit definitions */ | ||
1409 | #define FAC_OPT_FORCE_SEMAPHORE BIT_15 | ||
1410 | #define FAC_OPT_REQUESTOR_ID BIT_14 | ||
1411 | #define FAC_OPT_CMD_SUBCODE 0xff | ||
1412 | |||
1413 | /* Flash access control command subcodes */ | ||
1414 | #define FAC_OPT_CMD_WRITE_PROTECT 0x00 | ||
1415 | #define FAC_OPT_CMD_WRITE_ENABLE 0x01 | ||
1416 | #define FAC_OPT_CMD_ERASE_SECTOR 0x02 | ||
1417 | #define FAC_OPT_CMD_LOCK_SEMAPHORE 0x03 | ||
1418 | #define FAC_OPT_CMD_UNLOCK_SEMAPHORE 0x04 | ||
1419 | #define FAC_OPT_CMD_GET_SECTOR_SIZE 0x05 | ||
1406 | 1420 | ||
1407 | struct nvram_81xx { | 1421 | struct nvram_81xx { |
1408 | /* NVRAM header. */ | 1422 | /* NVRAM header. */ |
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index af36238859d4..4d52bf1c2ada 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h | |||
@@ -269,6 +269,15 @@ extern int qla84xx_verify_chip(struct scsi_qla_host *, uint16_t *); | |||
269 | 269 | ||
270 | extern int qla81xx_idc_ack(scsi_qla_host_t *, uint16_t *); | 270 | extern int qla81xx_idc_ack(scsi_qla_host_t *, uint16_t *); |
271 | 271 | ||
272 | extern int | ||
273 | qla81xx_fac_get_sector_size(scsi_qla_host_t *, uint32_t *); | ||
274 | |||
275 | extern int | ||
276 | qla81xx_fac_do_write_enable(scsi_qla_host_t *, int); | ||
277 | |||
278 | extern int | ||
279 | qla81xx_fac_erase_sector(scsi_qla_host_t *, uint32_t, uint32_t); | ||
280 | |||
272 | /* | 281 | /* |
273 | * Global Function Prototypes in qla_isr.c source file. | 282 | * Global Function Prototypes in qla_isr.c source file. |
274 | */ | 283 | */ |
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 0febfa648c34..c37888e8747d 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c | |||
@@ -1032,6 +1032,21 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) | |||
1032 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 1032 | spin_unlock_irqrestore(&ha->hardware_lock, flags); |
1033 | } | 1033 | } |
1034 | 1034 | ||
1035 | if (rval == QLA_SUCCESS && IS_FAC_REQUIRED(ha)) { | ||
1036 | uint32_t size; | ||
1037 | |||
1038 | rval = qla81xx_fac_get_sector_size(vha, &size); | ||
1039 | if (rval == QLA_SUCCESS) { | ||
1040 | ha->flags.fac_supported = 1; | ||
1041 | ha->fdt_block_size = size << 2; | ||
1042 | } else { | ||
1043 | qla_printk(KERN_ERR, ha, | ||
1044 | "Unsupported FAC firmware (%d.%02d.%02d).\n", | ||
1045 | ha->fw_major_version, ha->fw_minor_version, | ||
1046 | ha->fw_subminor_version); | ||
1047 | } | ||
1048 | } | ||
1049 | |||
1035 | if (rval) { | 1050 | if (rval) { |
1036 | DEBUG2_3(printk("scsi(%ld): Setup chip **** FAILED ****.\n", | 1051 | DEBUG2_3(printk("scsi(%ld): Setup chip **** FAILED ****.\n", |
1037 | vha->host_no)); | 1052 | vha->host_no)); |
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index b380c6fdbe40..2bc08d3b3537 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c | |||
@@ -3228,3 +3228,100 @@ qla81xx_idc_ack(scsi_qla_host_t *vha, uint16_t *mb) | |||
3228 | 3228 | ||
3229 | return rval; | 3229 | return rval; |
3230 | } | 3230 | } |
3231 | |||
3232 | int | ||
3233 | qla81xx_fac_get_sector_size(scsi_qla_host_t *vha, uint32_t *sector_size) | ||
3234 | { | ||
3235 | int rval; | ||
3236 | mbx_cmd_t mc; | ||
3237 | mbx_cmd_t *mcp = &mc; | ||
3238 | |||
3239 | if (!IS_QLA81XX(vha->hw)) | ||
3240 | return QLA_FUNCTION_FAILED; | ||
3241 | |||
3242 | DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); | ||
3243 | |||
3244 | mcp->mb[0] = MBC_FLASH_ACCESS_CTRL; | ||
3245 | mcp->mb[1] = FAC_OPT_CMD_GET_SECTOR_SIZE; | ||
3246 | mcp->out_mb = MBX_1|MBX_0; | ||
3247 | mcp->in_mb = MBX_1|MBX_0; | ||
3248 | mcp->tov = MBX_TOV_SECONDS; | ||
3249 | mcp->flags = 0; | ||
3250 | rval = qla2x00_mailbox_command(vha, mcp); | ||
3251 | |||
3252 | if (rval != QLA_SUCCESS) { | ||
3253 | DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n", | ||
3254 | __func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1])); | ||
3255 | } else { | ||
3256 | DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no)); | ||
3257 | *sector_size = mcp->mb[1]; | ||
3258 | } | ||
3259 | |||
3260 | return rval; | ||
3261 | } | ||
3262 | |||
3263 | int | ||
3264 | qla81xx_fac_do_write_enable(scsi_qla_host_t *vha, int enable) | ||
3265 | { | ||
3266 | int rval; | ||
3267 | mbx_cmd_t mc; | ||
3268 | mbx_cmd_t *mcp = &mc; | ||
3269 | |||
3270 | if (!IS_QLA81XX(vha->hw)) | ||
3271 | return QLA_FUNCTION_FAILED; | ||
3272 | |||
3273 | DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); | ||
3274 | |||
3275 | mcp->mb[0] = MBC_FLASH_ACCESS_CTRL; | ||
3276 | mcp->mb[1] = enable ? FAC_OPT_CMD_WRITE_ENABLE : | ||
3277 | FAC_OPT_CMD_WRITE_PROTECT; | ||
3278 | mcp->out_mb = MBX_1|MBX_0; | ||
3279 | mcp->in_mb = MBX_1|MBX_0; | ||
3280 | mcp->tov = MBX_TOV_SECONDS; | ||
3281 | mcp->flags = 0; | ||
3282 | rval = qla2x00_mailbox_command(vha, mcp); | ||
3283 | |||
3284 | if (rval != QLA_SUCCESS) { | ||
3285 | DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n", | ||
3286 | __func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1])); | ||
3287 | } else { | ||
3288 | DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no)); | ||
3289 | } | ||
3290 | |||
3291 | return rval; | ||
3292 | } | ||
3293 | |||
3294 | int | ||
3295 | qla81xx_fac_erase_sector(scsi_qla_host_t *vha, uint32_t start, uint32_t finish) | ||
3296 | { | ||
3297 | int rval; | ||
3298 | mbx_cmd_t mc; | ||
3299 | mbx_cmd_t *mcp = &mc; | ||
3300 | |||
3301 | if (!IS_QLA81XX(vha->hw)) | ||
3302 | return QLA_FUNCTION_FAILED; | ||
3303 | |||
3304 | DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); | ||
3305 | |||
3306 | mcp->mb[0] = MBC_FLASH_ACCESS_CTRL; | ||
3307 | mcp->mb[1] = FAC_OPT_CMD_ERASE_SECTOR; | ||
3308 | mcp->mb[2] = LSW(start); | ||
3309 | mcp->mb[3] = MSW(start); | ||
3310 | mcp->mb[4] = LSW(finish); | ||
3311 | mcp->mb[5] = MSW(finish); | ||
3312 | mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; | ||
3313 | mcp->in_mb = MBX_2|MBX_1|MBX_0; | ||
3314 | mcp->tov = MBX_TOV_SECONDS; | ||
3315 | mcp->flags = 0; | ||
3316 | rval = qla2x00_mailbox_command(vha, mcp); | ||
3317 | |||
3318 | if (rval != QLA_SUCCESS) { | ||
3319 | DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x " | ||
3320 | "mb[2]=%x.\n", __func__, vha->host_no, rval, mcp->mb[0], | ||
3321 | mcp->mb[1], mcp->mb[2])); | ||
3322 | } else { | ||
3323 | DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no)); | ||
3324 | } | ||
3325 | |||
3326 | return rval; | ||
3327 | } | ||
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 5b24af86aaf0..ff5aa75109fc 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c | |||
@@ -931,31 +931,41 @@ done: | |||
931 | ha->npiv_info = NULL; | 931 | ha->npiv_info = NULL; |
932 | } | 932 | } |
933 | 933 | ||
934 | static void | 934 | static int |
935 | qla24xx_unprotect_flash(struct qla_hw_data *ha) | 935 | qla24xx_unprotect_flash(scsi_qla_host_t *vha) |
936 | { | 936 | { |
937 | struct qla_hw_data *ha = vha->hw; | ||
937 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; | 938 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; |
938 | 939 | ||
940 | if (ha->flags.fac_supported) | ||
941 | return qla81xx_fac_do_write_enable(vha, 1); | ||
942 | |||
939 | /* Enable flash write. */ | 943 | /* Enable flash write. */ |
940 | WRT_REG_DWORD(®->ctrl_status, | 944 | WRT_REG_DWORD(®->ctrl_status, |
941 | RD_REG_DWORD(®->ctrl_status) | CSRX_FLASH_ENABLE); | 945 | RD_REG_DWORD(®->ctrl_status) | CSRX_FLASH_ENABLE); |
942 | RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ | 946 | RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ |
943 | 947 | ||
944 | if (!ha->fdt_wrt_disable) | 948 | if (!ha->fdt_wrt_disable) |
945 | return; | 949 | goto done; |
946 | 950 | ||
947 | /* Disable flash write-protection, first clear SR protection bit */ | 951 | /* Disable flash write-protection, first clear SR protection bit */ |
948 | qla24xx_write_flash_dword(ha, flash_conf_addr(ha, 0x101), 0); | 952 | qla24xx_write_flash_dword(ha, flash_conf_addr(ha, 0x101), 0); |
949 | /* Then write zero again to clear remaining SR bits.*/ | 953 | /* Then write zero again to clear remaining SR bits.*/ |
950 | qla24xx_write_flash_dword(ha, flash_conf_addr(ha, 0x101), 0); | 954 | qla24xx_write_flash_dword(ha, flash_conf_addr(ha, 0x101), 0); |
955 | done: | ||
956 | return QLA_SUCCESS; | ||
951 | } | 957 | } |
952 | 958 | ||
953 | static void | 959 | static int |
954 | qla24xx_protect_flash(struct qla_hw_data *ha) | 960 | qla24xx_protect_flash(scsi_qla_host_t *vha) |
955 | { | 961 | { |
956 | uint32_t cnt; | 962 | uint32_t cnt; |
963 | struct qla_hw_data *ha = vha->hw; | ||
957 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; | 964 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; |
958 | 965 | ||
966 | if (ha->flags.fac_supported) | ||
967 | return qla81xx_fac_do_write_enable(vha, 0); | ||
968 | |||
959 | if (!ha->fdt_wrt_disable) | 969 | if (!ha->fdt_wrt_disable) |
960 | goto skip_wrt_protect; | 970 | goto skip_wrt_protect; |
961 | 971 | ||
@@ -973,6 +983,26 @@ skip_wrt_protect: | |||
973 | WRT_REG_DWORD(®->ctrl_status, | 983 | WRT_REG_DWORD(®->ctrl_status, |
974 | RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); | 984 | RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); |
975 | RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ | 985 | RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ |
986 | |||
987 | return QLA_SUCCESS; | ||
988 | } | ||
989 | |||
990 | static int | ||
991 | qla24xx_erase_sector(scsi_qla_host_t *vha, uint32_t fdata) | ||
992 | { | ||
993 | struct qla_hw_data *ha = vha->hw; | ||
994 | uint32_t start, finish; | ||
995 | |||
996 | if (ha->flags.fac_supported) { | ||
997 | start = fdata >> 2; | ||
998 | finish = start + (ha->fdt_block_size >> 2) - 1; | ||
999 | return qla81xx_fac_erase_sector(vha, flash_data_addr(ha, | ||
1000 | start), flash_data_addr(ha, finish)); | ||
1001 | } | ||
1002 | |||
1003 | return qla24xx_write_flash_dword(ha, ha->fdt_erase_cmd, | ||
1004 | (fdata & 0xff00) | ((fdata << 16) & 0xff0000) | | ||
1005 | ((fdata >> 16) & 0xff)); | ||
976 | } | 1006 | } |
977 | 1007 | ||
978 | static int | 1008 | static int |
@@ -987,8 +1017,6 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, | |||
987 | void *optrom = NULL; | 1017 | void *optrom = NULL; |
988 | struct qla_hw_data *ha = vha->hw; | 1018 | struct qla_hw_data *ha = vha->hw; |
989 | 1019 | ||
990 | ret = QLA_SUCCESS; | ||
991 | |||
992 | /* Prepare burst-capable write on supported ISPs. */ | 1020 | /* Prepare burst-capable write on supported ISPs. */ |
993 | if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && !(faddr & 0xfff) && | 1021 | if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && !(faddr & 0xfff) && |
994 | dwords > OPTROM_BURST_DWORDS) { | 1022 | dwords > OPTROM_BURST_DWORDS) { |
@@ -1004,7 +1032,12 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, | |||
1004 | rest_addr = (ha->fdt_block_size >> 2) - 1; | 1032 | rest_addr = (ha->fdt_block_size >> 2) - 1; |
1005 | sec_mask = ~rest_addr; | 1033 | sec_mask = ~rest_addr; |
1006 | 1034 | ||
1007 | qla24xx_unprotect_flash(ha); | 1035 | ret = qla24xx_unprotect_flash(vha); |
1036 | if (ret != QLA_SUCCESS) { | ||
1037 | qla_printk(KERN_WARNING, ha, | ||
1038 | "Unable to unprotect flash for update.\n"); | ||
1039 | goto done; | ||
1040 | } | ||
1008 | 1041 | ||
1009 | for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) { | 1042 | for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) { |
1010 | fdata = (faddr & sec_mask) << 2; | 1043 | fdata = (faddr & sec_mask) << 2; |
@@ -1017,9 +1050,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, | |||
1017 | ha->fdt_unprotect_sec_cmd, | 1050 | ha->fdt_unprotect_sec_cmd, |
1018 | (fdata & 0xff00) | ((fdata << 16) & | 1051 | (fdata & 0xff00) | ((fdata << 16) & |
1019 | 0xff0000) | ((fdata >> 16) & 0xff)); | 1052 | 0xff0000) | ((fdata >> 16) & 0xff)); |
1020 | ret = qla24xx_write_flash_dword(ha, ha->fdt_erase_cmd, | 1053 | ret = qla24xx_erase_sector(vha, fdata); |
1021 | (fdata & 0xff00) |((fdata << 16) & | ||
1022 | 0xff0000) | ((fdata >> 16) & 0xff)); | ||
1023 | if (ret != QLA_SUCCESS) { | 1054 | if (ret != QLA_SUCCESS) { |
1024 | DEBUG9(qla_printk("Unable to erase sector: " | 1055 | DEBUG9(qla_printk("Unable to erase sector: " |
1025 | "address=%x.\n", faddr)); | 1056 | "address=%x.\n", faddr)); |
@@ -1073,8 +1104,11 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, | |||
1073 | 0xff0000) | ((fdata >> 16) & 0xff)); | 1104 | 0xff0000) | ((fdata >> 16) & 0xff)); |
1074 | } | 1105 | } |
1075 | 1106 | ||
1076 | qla24xx_protect_flash(ha); | 1107 | ret = qla24xx_protect_flash(vha); |
1077 | 1108 | if (ret != QLA_SUCCESS) | |
1109 | qla_printk(KERN_WARNING, ha, | ||
1110 | "Unable to protect flash after update.\n"); | ||
1111 | done: | ||
1078 | if (optrom) | 1112 | if (optrom) |
1079 | dma_free_coherent(&ha->pdev->dev, | 1113 | dma_free_coherent(&ha->pdev->dev, |
1080 | OPTROM_BURST_SIZE, optrom, optrom_dma); | 1114 | OPTROM_BURST_SIZE, optrom, optrom_dma); |