aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorJoe Carnuccio <joe.carnuccio@qlogic.com>2009-03-24 12:08:06 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2009-04-03 10:22:48 -0400
commit1d2874de809a14e6780246b99a18bbc0fc0a8f2a (patch)
tree0f9dc305dc6f802c27bcef6edc607832864b7687 /drivers/scsi
parentb9978769877c6c90c8d6777df13b9ae427af40b7 (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.h3
-rw-r--r--drivers/scsi/qla2xxx/qla_fw.h14
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h9
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c15
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c97
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c60
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
1407struct nvram_81xx { 1421struct 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
270extern int qla81xx_idc_ack(scsi_qla_host_t *, uint16_t *); 270extern int qla81xx_idc_ack(scsi_qla_host_t *, uint16_t *);
271 271
272extern int
273qla81xx_fac_get_sector_size(scsi_qla_host_t *, uint32_t *);
274
275extern int
276qla81xx_fac_do_write_enable(scsi_qla_host_t *, int);
277
278extern int
279qla81xx_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
3232int
3233qla81xx_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
3263int
3264qla81xx_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
3294int
3295qla81xx_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
934static void 934static int
935qla24xx_unprotect_flash(struct qla_hw_data *ha) 935qla24xx_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(&reg->ctrl_status, 944 WRT_REG_DWORD(&reg->ctrl_status,
941 RD_REG_DWORD(&reg->ctrl_status) | CSRX_FLASH_ENABLE); 945 RD_REG_DWORD(&reg->ctrl_status) | CSRX_FLASH_ENABLE);
942 RD_REG_DWORD(&reg->ctrl_status); /* PCI Posting. */ 946 RD_REG_DWORD(&reg->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);
955done:
956 return QLA_SUCCESS;
951} 957}
952 958
953static void 959static int
954qla24xx_protect_flash(struct qla_hw_data *ha) 960qla24xx_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(&reg->ctrl_status, 983 WRT_REG_DWORD(&reg->ctrl_status,
974 RD_REG_DWORD(&reg->ctrl_status) & ~CSRX_FLASH_ENABLE); 984 RD_REG_DWORD(&reg->ctrl_status) & ~CSRX_FLASH_ENABLE);
975 RD_REG_DWORD(&reg->ctrl_status); /* PCI Posting. */ 985 RD_REG_DWORD(&reg->ctrl_status); /* PCI Posting. */
986
987 return QLA_SUCCESS;
988}
989
990static int
991qla24xx_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
978static int 1008static 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");
1111done:
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);