[SCSI] qla2xxx: Add ISP24xx flash-manipulation routines.
authorAndrew Vasquez <andrew.vasquez@qlogic.com>
Wed, 6 Jul 2005 17:31:07 +0000 (10:31 -0700)
committerJames Bottomley <jejb@mulgrave.(none)>
Thu, 14 Jul 2005 14:56:54 +0000 (10:56 -0400)
Add ISP24xx flash-manipulation routines.

Add read/write flash manipulation routines for the ISP24xx.
Update sysfs NVRAM objects to use generalized accessor
functions.

Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_sup.c

index 30c381c3abcc508cbe5818522cec8c1197d59ea9..9361f4255e62486495b1053498905fc004727d09 100644 (file)
@@ -118,23 +118,15 @@ qla2x00_sysfs_read_nvram(struct kobject *kobj, char *buf, loff_t off,
 {
        struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
            struct device, kobj)));
-       uint16_t        *witer;
        unsigned long   flags;
-       uint16_t        cnt;
 
-       if (!capable(CAP_SYS_ADMIN) || off != 0 || count != sizeof(nvram_t))
+       if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->nvram_size)
                return 0;
 
        /* Read NVRAM. */
        spin_lock_irqsave(&ha->hardware_lock, flags);
-       qla2x00_lock_nvram_access(ha);
-       witer = (uint16_t *)buf;
-       for (cnt = 0; cnt < count / 2; cnt++) {
-               *witer = cpu_to_le16(qla2x00_get_nvram_word(ha,
-                   cnt+ha->nvram_base));
-               witer++;
-       }
-       qla2x00_unlock_nvram_access(ha);
+       ha->isp_ops.read_nvram(ha, (uint8_t *)buf, ha->nvram_base,
+           ha->nvram_size);
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
        return (count);
@@ -146,34 +138,38 @@ qla2x00_sysfs_write_nvram(struct kobject *kobj, char *buf, loff_t off,
 {
        struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
            struct device, kobj)));
-       uint8_t         *iter;
-       uint16_t        *witer;
        unsigned long   flags;
        uint16_t        cnt;
-       uint8_t         chksum;
 
-       if (!capable(CAP_SYS_ADMIN) || off != 0 || count != sizeof(nvram_t))
+       if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->nvram_size)
                return 0;
 
        /* Checksum NVRAM. */
-       iter = (uint8_t *)buf;
-       chksum = 0;
-       for (cnt = 0; cnt < count - 1; cnt++)
-               chksum += *iter++;
-       chksum = ~chksum + 1;
-       *iter = chksum;
+       if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) {
+               uint32_t *iter;
+               uint32_t chksum;
+
+               iter = (uint32_t *)buf;
+               chksum = 0;
+               for (cnt = 0; cnt < ((count >> 2) - 1); cnt++)
+                       chksum += le32_to_cpu(*iter++);
+               chksum = ~chksum + 1;
+               *iter = cpu_to_le32(chksum);
+       } else {
+               uint8_t *iter;
+               uint8_t chksum;
+
+               iter = (uint8_t *)buf;
+               chksum = 0;
+               for (cnt = 0; cnt < count - 1; cnt++)
+                       chksum += *iter++;
+               chksum = ~chksum + 1;
+               *iter = chksum;
+       }
 
        /* Write NVRAM. */
        spin_lock_irqsave(&ha->hardware_lock, flags);
-       qla2x00_lock_nvram_access(ha);
-       qla2x00_release_nvram_protection(ha);
-       witer = (uint16_t *)buf;
-       for (cnt = 0; cnt < count / 2; cnt++) {
-               qla2x00_write_nvram_word(ha, cnt+ha->nvram_base,
-                   cpu_to_le16(*witer));
-               witer++;
-       }
-       qla2x00_unlock_nvram_access(ha);
+       ha->isp_ops.write_nvram(ha, (uint8_t *)buf, ha->nvram_base, count);
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
        return (count);
@@ -185,7 +181,7 @@ static struct bin_attribute sysfs_nvram_attr = {
                .mode = S_IRUSR | S_IWUSR,
                .owner = THIS_MODULE,
        },
-       .size = sizeof(nvram_t),
+       .size = 0,
        .read = qla2x00_sysfs_read_nvram,
        .write = qla2x00_sysfs_write_nvram,
 };
@@ -196,6 +192,7 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha)
        struct Scsi_Host *host = ha->host;
 
        sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_fw_dump_attr);
+       sysfs_nvram_attr.size = ha->nvram_size;
        sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_attr);
 }
 
index 574446c0892a747dc73c23d484b8b22a9198a40c..0dd732486e243d137ca339689b1a4f539978103c 100644 (file)
@@ -220,6 +220,17 @@ extern void qla2x00_unlock_nvram_access(scsi_qla_host_t *);
 extern void qla2x00_release_nvram_protection(scsi_qla_host_t *);
 extern uint16_t qla2x00_get_nvram_word(scsi_qla_host_t *, uint32_t);
 extern void qla2x00_write_nvram_word(scsi_qla_host_t *, uint32_t, uint16_t);
+extern uint32_t *qla24xx_read_flash_data(scsi_qla_host_t *, uint32_t *,
+    uint32_t, uint32_t);
+extern uint8_t *qla2x00_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
+    uint32_t);
+extern uint8_t *qla24xx_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
+    uint32_t);
+extern int qla2x00_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
+    uint32_t);
+extern int qla24xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
+    uint32_t);
+
 /*
  * Global Function Prototypes in qla_dbg.c source file.
  */
index a325b66ea41c4beac912fae38e5053e084830b6f..9e6d0511925350b50f09d232786fff373a0ff29f 100644 (file)
@@ -1187,6 +1187,8 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info)
        ha->isp_ops.calc_req_entries    = qla2x00_calc_iocbs_32;
        ha->isp_ops.build_iocbs         = qla2x00_build_scsi_iocbs_32;
        ha->isp_ops.prep_ms_iocb        = qla2x00_prep_ms_iocb;
+       ha->isp_ops.read_nvram          = qla2x00_read_nvram_data;
+       ha->isp_ops.write_nvram         = qla2x00_write_nvram_data;
        ha->isp_ops.fw_dump             = qla2100_fw_dump;
        ha->isp_ops.ascii_fw_dump       = qla2100_ascii_fw_dump;
        if (IS_QLA2100(ha)) {
index cf2a6bc444d2d217412076aba9ba504ebc21eea7..c95ef2bb089a0ea9512d21ea510dbd73e893f55e 100644 (file)
@@ -78,54 +78,6 @@ qla2x00_unlock_nvram_access(scsi_qla_host_t *ha)
        }
 }
 
-/**
- * qla2x00_release_nvram_protection() - 
- * @ha: HA context
- */
-void
-qla2x00_release_nvram_protection(scsi_qla_host_t *ha)
-{
-       struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
-       uint32_t word;
-
-       /* Release NVRAM write protection. */
-       if (IS_QLA2322(ha) || IS_QLA6322(ha)) {
-               /* Write enable. */
-               qla2x00_nv_write(ha, NVR_DATA_OUT);
-               qla2x00_nv_write(ha, 0);
-               qla2x00_nv_write(ha, 0);
-               for (word = 0; word < 8; word++)
-                       qla2x00_nv_write(ha, NVR_DATA_OUT);
-
-               qla2x00_nv_deselect(ha);
-
-               /* Enable protection register. */
-               qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT);
-               qla2x00_nv_write(ha, NVR_PR_ENABLE);
-               qla2x00_nv_write(ha, NVR_PR_ENABLE);
-               for (word = 0; word < 8; word++)
-                       qla2x00_nv_write(ha, NVR_DATA_OUT | NVR_PR_ENABLE);
-
-               qla2x00_nv_deselect(ha);
-
-               /* Clear protection register (ffff is cleared). */
-               qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT);
-               qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT);
-               qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT);
-               for (word = 0; word < 8; word++)
-                       qla2x00_nv_write(ha, NVR_DATA_OUT | NVR_PR_ENABLE);
-
-               qla2x00_nv_deselect(ha);
-
-               /* Wait for NVRAM to become ready. */
-               WRT_REG_WORD(&reg->nvram, NVR_SELECT);
-               do {
-                       NVRAM_DELAY();
-                       word = RD_REG_WORD(&reg->nvram);
-               } while ((word & NVR_DATA_IN) == 0);
-       }
-}
-
 /**
  * qla2x00_get_nvram_word() - Calculates word position in NVRAM and calls the
  *     request routine to get the word from NVRAM.
@@ -202,6 +154,64 @@ qla2x00_write_nvram_word(scsi_qla_host_t *ha, uint32_t addr, uint16_t data)
        qla2x00_nv_deselect(ha);
 }
 
+static int
+qla2x00_write_nvram_word_tmo(scsi_qla_host_t *ha, uint32_t addr, uint16_t data,
+    uint32_t tmo)
+{
+       int ret, count;
+       uint16_t word;
+       uint32_t nv_cmd;
+       struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+
+       ret = QLA_SUCCESS;
+
+       qla2x00_nv_write(ha, NVR_DATA_OUT);
+       qla2x00_nv_write(ha, 0);
+       qla2x00_nv_write(ha, 0);
+
+       for (word = 0; word < 8; word++)
+               qla2x00_nv_write(ha, NVR_DATA_OUT);
+
+       qla2x00_nv_deselect(ha);
+
+       /* Write data */
+       nv_cmd = (addr << 16) | NV_WRITE_OP;
+       nv_cmd |= data;
+       nv_cmd <<= 5;
+       for (count = 0; count < 27; count++) {
+               if (nv_cmd & BIT_31)
+                       qla2x00_nv_write(ha, NVR_DATA_OUT);
+               else
+                       qla2x00_nv_write(ha, 0);
+
+               nv_cmd <<= 1;
+       }
+
+       qla2x00_nv_deselect(ha);
+
+       /* Wait for NVRAM to become ready */
+       WRT_REG_WORD(&reg->nvram, NVR_SELECT);
+       do {
+               NVRAM_DELAY();
+               word = RD_REG_WORD(&reg->nvram);
+               if (!--tmo) {
+                       ret = QLA_FUNCTION_FAILED;
+                       break;
+               }
+       } while ((word & NVR_DATA_IN) == 0);
+
+       qla2x00_nv_deselect(ha);
+
+       /* Disable writes */
+       qla2x00_nv_write(ha, NVR_DATA_OUT);
+       for (count = 0; count < 10; count++)
+               qla2x00_nv_write(ha, 0);
+
+       qla2x00_nv_deselect(ha);
+
+       return ret;
+}
+
 /**
  * qla2x00_nvram_request() - Sends read command to NVRAM and gets data from
  *     NVRAM.
@@ -292,3 +302,435 @@ qla2x00_nv_write(scsi_qla_host_t *ha, uint16_t data)
        NVRAM_DELAY();
 }
 
+/**
+ * qla2x00_clear_nvram_protection() -
+ * @ha: HA context
+ */
+static int
+qla2x00_clear_nvram_protection(scsi_qla_host_t *ha)
+{
+       int ret, stat;
+       struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+       uint32_t word;
+       uint16_t wprot, wprot_old;
+
+       /* Clear NVRAM write protection. */
+       ret = QLA_FUNCTION_FAILED;
+       wprot_old = cpu_to_le16(qla2x00_get_nvram_word(ha, 0));
+       stat = qla2x00_write_nvram_word_tmo(ha, 0,
+           __constant_cpu_to_le16(0x1234), 100000);
+       wprot = cpu_to_le16(qla2x00_get_nvram_word(ha, 0));
+       if (stat != QLA_SUCCESS || wprot != __constant_cpu_to_le16(0x1234)) {
+               /* Write enable. */
+               qla2x00_nv_write(ha, NVR_DATA_OUT);
+               qla2x00_nv_write(ha, 0);
+               qla2x00_nv_write(ha, 0);
+               for (word = 0; word < 8; word++)
+                       qla2x00_nv_write(ha, NVR_DATA_OUT);
+
+               qla2x00_nv_deselect(ha);
+
+               /* Enable protection register. */
+               qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT);
+               qla2x00_nv_write(ha, NVR_PR_ENABLE);
+               qla2x00_nv_write(ha, NVR_PR_ENABLE);
+               for (word = 0; word < 8; word++)
+                       qla2x00_nv_write(ha, NVR_DATA_OUT | NVR_PR_ENABLE);
+
+               qla2x00_nv_deselect(ha);
+
+               /* Clear protection register (ffff is cleared). */
+               qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT);
+               qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT);
+               qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT);
+               for (word = 0; word < 8; word++)
+                       qla2x00_nv_write(ha, NVR_DATA_OUT | NVR_PR_ENABLE);
+
+               qla2x00_nv_deselect(ha);
+
+               /* Wait for NVRAM to become ready. */
+               WRT_REG_WORD(&reg->nvram, NVR_SELECT);
+               do {
+                       NVRAM_DELAY();
+                       word = RD_REG_WORD(&reg->nvram);
+               } while ((word & NVR_DATA_IN) == 0);
+
+               ret = QLA_SUCCESS;
+       } else
+               qla2x00_write_nvram_word(ha, 0, wprot_old);
+
+       return ret;
+}
+
+static void
+qla2x00_set_nvram_protection(scsi_qla_host_t *ha, int stat)
+{
+       struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+       uint32_t word;
+
+       if (stat != QLA_SUCCESS)
+               return;
+
+       /* Set NVRAM write protection. */
+       /* Write enable. */
+       qla2x00_nv_write(ha, NVR_DATA_OUT);
+       qla2x00_nv_write(ha, 0);
+       qla2x00_nv_write(ha, 0);
+       for (word = 0; word < 8; word++)
+               qla2x00_nv_write(ha, NVR_DATA_OUT);
+
+       qla2x00_nv_deselect(ha);
+
+       /* Enable protection register. */
+       qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT);
+       qla2x00_nv_write(ha, NVR_PR_ENABLE);
+       qla2x00_nv_write(ha, NVR_PR_ENABLE);
+       for (word = 0; word < 8; word++)
+               qla2x00_nv_write(ha, NVR_DATA_OUT | NVR_PR_ENABLE);
+
+       qla2x00_nv_deselect(ha);
+
+       /* Enable protection register. */
+       qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT);
+       qla2x00_nv_write(ha, NVR_PR_ENABLE);
+       qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT);
+       for (word = 0; word < 8; word++)
+               qla2x00_nv_write(ha, NVR_PR_ENABLE);
+
+       qla2x00_nv_deselect(ha);
+
+       /* Wait for NVRAM to become ready. */
+       WRT_REG_WORD(&reg->nvram, NVR_SELECT);
+       do {
+               NVRAM_DELAY();
+               word = RD_REG_WORD(&reg->nvram);
+       } while ((word & NVR_DATA_IN) == 0);
+}
+
+
+/*****************************************************************************/
+/* Flash Manipulation Routines                                               */
+/*****************************************************************************/
+
+static inline uint32_t
+flash_conf_to_access_addr(uint32_t faddr)
+{
+       return FARX_ACCESS_FLASH_CONF | faddr;
+}
+
+static inline uint32_t
+flash_data_to_access_addr(uint32_t faddr)
+{
+       return FARX_ACCESS_FLASH_DATA | faddr;
+}
+
+static inline uint32_t
+nvram_conf_to_access_addr(uint32_t naddr)
+{
+       return FARX_ACCESS_NVRAM_CONF | naddr;
+}
+
+static inline uint32_t
+nvram_data_to_access_addr(uint32_t naddr)
+{
+       return FARX_ACCESS_NVRAM_DATA | naddr;
+}
+
+uint32_t
+qla24xx_read_flash_dword(scsi_qla_host_t *ha, uint32_t addr)
+{
+       int rval;
+       uint32_t cnt, data;
+       struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+
+       WRT_REG_DWORD(&reg->flash_addr, addr & ~FARX_DATA_FLAG);
+       /* Wait for READ cycle to complete. */
+       rval = QLA_SUCCESS;
+       for (cnt = 3000;
+           (RD_REG_DWORD(&reg->flash_addr) & FARX_DATA_FLAG) == 0 &&
+           rval == QLA_SUCCESS; cnt--) {
+               if (cnt)
+                       udelay(10);
+               else
+                       rval = QLA_FUNCTION_TIMEOUT;
+       }
+
+       /* TODO: What happens if we time out? */
+       data = 0xDEADDEAD;
+       if (rval == QLA_SUCCESS)
+               data = RD_REG_DWORD(&reg->flash_data);
+
+       return data;
+}
+
+uint32_t *
+qla24xx_read_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
+    uint32_t dwords)
+{
+       uint32_t i;
+       struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+
+       /* Pause RISC. */
+       WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_PAUSE);
+       RD_REG_DWORD(&reg->hccr);               /* PCI Posting. */
+
+       /* Dword reads to flash. */
+       for (i = 0; i < dwords; i++, faddr++)
+               dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha,
+                   flash_data_to_access_addr(faddr)));
+
+       /* Release RISC pause. */
+       WRT_REG_DWORD(&reg->hccr, HCCRX_REL_RISC_PAUSE);
+       RD_REG_DWORD(&reg->hccr);               /* PCI Posting. */
+
+       return dwptr;
+}
+
+int
+qla24xx_write_flash_dword(scsi_qla_host_t *ha, uint32_t addr, uint32_t data)
+{
+       int rval;
+       uint32_t cnt;
+       struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+
+       WRT_REG_DWORD(&reg->flash_data, data);
+       RD_REG_DWORD(&reg->flash_data);         /* PCI Posting. */
+       WRT_REG_DWORD(&reg->flash_addr, addr | FARX_DATA_FLAG);
+       /* Wait for Write cycle to complete. */
+       rval = QLA_SUCCESS;
+       for (cnt = 500000; (RD_REG_DWORD(&reg->flash_addr) & FARX_DATA_FLAG) &&
+           rval == QLA_SUCCESS; cnt--) {
+               if (cnt)
+                       udelay(10);
+               else
+                       rval = QLA_FUNCTION_TIMEOUT;
+       }
+       return rval;
+}
+
+void
+qla24xx_get_flash_manufacturer(scsi_qla_host_t *ha, uint8_t *man_id,
+    uint8_t *flash_id)
+{
+       uint32_t ids;
+
+       ids = qla24xx_read_flash_dword(ha, flash_data_to_access_addr(0xd03ab));
+       *man_id = LSB(ids);
+       *flash_id = MSB(ids);
+}
+
+int
+qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
+    uint32_t dwords)
+{
+       int ret;
+       uint32_t liter;
+       uint32_t sec_mask, rest_addr, conf_addr;
+       uint32_t fdata;
+       uint8_t man_id, flash_id;
+       struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+
+       ret = QLA_SUCCESS;
+
+       /* Pause RISC. */
+       WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_PAUSE);
+       RD_REG_DWORD(&reg->hccr);               /* PCI Posting. */
+
+       qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id);
+       DEBUG9(printk("%s(%ld): Flash man_id=%d flash_id=%d\n", __func__,
+           ha->host_no, man_id, flash_id));
+
+       conf_addr = flash_conf_to_access_addr(0x03d8);
+       switch (man_id) {
+       case 0xbf: // STT flash
+               rest_addr = 0x1fff;
+               sec_mask = 0x3e000;
+               if (flash_id == 0x80)
+                       conf_addr = flash_conf_to_access_addr(0x0352);
+               break;
+       case 0x13: // ST M25P80
+               rest_addr = 0x3fff;
+               sec_mask = 0x3c000;
+               break;
+       default:
+               // Default to 64 kb sector size
+               rest_addr = 0x3fff;
+               sec_mask = 0x3c000;
+               break;
+       }
+
+       /* Enable flash write. */
+       WRT_REG_DWORD(&reg->ctrl_status,
+           RD_REG_DWORD(&reg->ctrl_status) | CSRX_FLASH_ENABLE);
+       RD_REG_DWORD(&reg->ctrl_status);        /* PCI Posting. */
+
+       /* Disable flash write-protection. */
+       qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0);
+
+       do {    /* Loop once to provide quick error exit. */
+               for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) {
+                       /* Are we at the beginning of a sector? */
+                       if ((faddr & rest_addr) == 0) {
+                               fdata = (faddr & sec_mask) << 2;
+                               ret = qla24xx_write_flash_dword(ha, conf_addr,
+                                   (fdata & 0xff00) |((fdata << 16) &
+                                   0xff0000) | ((fdata >> 16) & 0xff));
+                               if (ret != QLA_SUCCESS) {
+                                       DEBUG9(printk("%s(%ld) Unable to flash "
+                                           "sector: address=%x.\n", __func__,
+                                           ha->host_no, faddr));
+                                       break;
+                               }
+                       }
+                       ret = qla24xx_write_flash_dword(ha,
+                           flash_data_to_access_addr(faddr),
+                           cpu_to_le32(*dwptr));
+                       if (ret != QLA_SUCCESS) {
+                               DEBUG9(printk("%s(%ld) Unable to program flash "
+                                   "address=%x data=%x.\n", __func__,
+                                   ha->host_no, faddr, *dwptr));
+                               break;
+                       }
+               }
+       } while (0);
+
+       /* Disable flash write. */
+       WRT_REG_DWORD(&reg->ctrl_status,
+           RD_REG_DWORD(&reg->ctrl_status) & ~CSRX_FLASH_ENABLE);
+       RD_REG_DWORD(&reg->ctrl_status);        /* PCI Posting. */
+
+       /* Release RISC pause. */
+       WRT_REG_DWORD(&reg->hccr, HCCRX_REL_RISC_PAUSE);
+       RD_REG_DWORD(&reg->hccr);               /* PCI Posting. */
+
+       return ret;
+}
+
+uint8_t *
+qla2x00_read_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
+    uint32_t bytes)
+{
+       uint32_t i;
+       uint16_t *wptr;
+
+       /* Word reads to NVRAM via registers. */
+       wptr = (uint16_t *)buf;
+       qla2x00_lock_nvram_access(ha);
+       for (i = 0; i < bytes >> 1; i++, naddr++)
+               wptr[i] = cpu_to_le16(qla2x00_get_nvram_word(ha,
+                   naddr));
+       qla2x00_unlock_nvram_access(ha);
+
+       return buf;
+}
+
+uint8_t *
+qla24xx_read_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
+    uint32_t bytes)
+{
+       uint32_t i;
+       uint32_t *dwptr;
+       struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+
+       /* Pause RISC. */
+       WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_PAUSE);
+       RD_REG_DWORD(&reg->hccr);       /* PCI Posting. */
+
+       /* Dword reads to flash. */
+       dwptr = (uint32_t *)buf;
+       for (i = 0; i < bytes >> 2; i++, naddr++)
+               dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha,
+                   nvram_data_to_access_addr(naddr)));
+
+       /* Release RISC pause. */
+       WRT_REG_DWORD(&reg->hccr, HCCRX_REL_RISC_PAUSE);
+       RD_REG_DWORD(&reg->hccr);       /* PCI Posting. */
+
+       return buf;
+}
+
+int
+qla2x00_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
+    uint32_t bytes)
+{
+       int ret, stat;
+       uint32_t i;
+       uint16_t *wptr;
+
+       ret = QLA_SUCCESS;
+
+       qla2x00_lock_nvram_access(ha);
+
+       /* Disable NVRAM write-protection. */
+       stat = qla2x00_clear_nvram_protection(ha);
+
+       wptr = (uint16_t *)buf;
+       for (i = 0; i < bytes >> 1; i++, naddr++) {
+               qla2x00_write_nvram_word(ha, naddr,
+                   cpu_to_le16(*wptr));
+               wptr++;
+       }
+
+       /* Enable NVRAM write-protection. */
+       qla2x00_set_nvram_protection(ha, stat);
+
+       qla2x00_unlock_nvram_access(ha);
+
+       return ret;
+}
+
+int
+qla24xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
+    uint32_t bytes)
+{
+       int ret;
+       uint32_t i;
+       uint32_t *dwptr;
+       struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+
+       ret = QLA_SUCCESS;
+
+       /* Pause RISC. */
+       WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_PAUSE);
+       RD_REG_DWORD(&reg->hccr);               /* PCI Posting. */
+
+       /* Enable flash write. */
+       WRT_REG_DWORD(&reg->ctrl_status,
+           RD_REG_DWORD(&reg->ctrl_status) | CSRX_FLASH_ENABLE);
+       RD_REG_DWORD(&reg->ctrl_status);        /* PCI Posting. */
+
+       /* Disable NVRAM write-protection. */
+       qla24xx_write_flash_dword(ha, nvram_conf_to_access_addr(0x101),
+           0);
+       qla24xx_write_flash_dword(ha, nvram_conf_to_access_addr(0x101),
+           0);
+
+       /* Dword writes to flash. */
+       dwptr = (uint32_t *)buf;
+       for (i = 0; i < bytes >> 2; i++, naddr++, dwptr++) {
+               ret = qla24xx_write_flash_dword(ha,
+                   nvram_data_to_access_addr(naddr),
+                   cpu_to_le32(*dwptr));
+               if (ret != QLA_SUCCESS) {
+                       DEBUG9(printk("%s(%ld) Unable to program "
+                           "nvram address=%x data=%x.\n", __func__,
+                           ha->host_no, naddr, *dwptr));
+                       break;
+               }
+       }
+
+       /* Enable NVRAM write-protection. */
+       qla24xx_write_flash_dword(ha, nvram_conf_to_access_addr(0x101),
+           0x8c);
+
+       /* Disable flash write. */
+       WRT_REG_DWORD(&reg->ctrl_status,
+           RD_REG_DWORD(&reg->ctrl_status) & ~CSRX_FLASH_ENABLE);
+       RD_REG_DWORD(&reg->ctrl_status);        /* PCI Posting. */
+
+       /* Release RISC pause. */
+       WRT_REG_DWORD(&reg->hccr, HCCRX_REL_RISC_PAUSE);
+       RD_REG_DWORD(&reg->hccr);               /* PCI Posting. */
+
+       return ret;
+}