diff options
author | Ravi Anand <ravi.anand@qlogic.com> | 2006-05-17 18:08:49 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-05-20 10:40:41 -0400 |
commit | 45aeaf1e8e4552ef82d3ff7a06e526e6d635f767 (patch) | |
tree | 10001713a5e9ae01cccbad02ad61d55307a97acd /drivers/scsi/qla2xxx/qla_sup.c | |
parent | 57680080baf3a8e289fad7f9e3c43ed58309e1eb (diff) |
[SCSI] qla2xxx: Add support for new flash part.
Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_sup.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_sup.c | 93 |
1 files changed, 81 insertions, 12 deletions
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 8b0121dceb01..c71dbd5bd543 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c | |||
@@ -97,7 +97,7 @@ qla2x00_write_nvram_word(scsi_qla_host_t *ha, uint32_t addr, uint16_t data) | |||
97 | { | 97 | { |
98 | int count; | 98 | int count; |
99 | uint16_t word; | 99 | uint16_t word; |
100 | uint32_t nv_cmd; | 100 | uint32_t nv_cmd, wait_cnt; |
101 | struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; | 101 | struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; |
102 | 102 | ||
103 | qla2x00_nv_write(ha, NVR_DATA_OUT); | 103 | qla2x00_nv_write(ha, NVR_DATA_OUT); |
@@ -127,7 +127,13 @@ qla2x00_write_nvram_word(scsi_qla_host_t *ha, uint32_t addr, uint16_t data) | |||
127 | /* Wait for NVRAM to become ready */ | 127 | /* Wait for NVRAM to become ready */ |
128 | WRT_REG_WORD(®->nvram, NVR_SELECT); | 128 | WRT_REG_WORD(®->nvram, NVR_SELECT); |
129 | RD_REG_WORD(®->nvram); /* PCI Posting. */ | 129 | RD_REG_WORD(®->nvram); /* PCI Posting. */ |
130 | wait_cnt = NVR_WAIT_CNT; | ||
130 | do { | 131 | do { |
132 | if (!--wait_cnt) { | ||
133 | DEBUG9_10(printk("%s(%ld): NVRAM didn't go ready...\n", | ||
134 | __func__, ha->host_no)); | ||
135 | break; | ||
136 | } | ||
131 | NVRAM_DELAY(); | 137 | NVRAM_DELAY(); |
132 | word = RD_REG_WORD(®->nvram); | 138 | word = RD_REG_WORD(®->nvram); |
133 | } while ((word & NVR_DATA_IN) == 0); | 139 | } while ((word & NVR_DATA_IN) == 0); |
@@ -301,16 +307,17 @@ qla2x00_clear_nvram_protection(scsi_qla_host_t *ha) | |||
301 | { | 307 | { |
302 | int ret, stat; | 308 | int ret, stat; |
303 | struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; | 309 | struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; |
304 | uint32_t word; | 310 | uint32_t word, wait_cnt; |
305 | uint16_t wprot, wprot_old; | 311 | uint16_t wprot, wprot_old; |
306 | 312 | ||
307 | /* Clear NVRAM write protection. */ | 313 | /* Clear NVRAM write protection. */ |
308 | ret = QLA_FUNCTION_FAILED; | 314 | ret = QLA_FUNCTION_FAILED; |
309 | wprot_old = cpu_to_le16(qla2x00_get_nvram_word(ha, 0)); | 315 | |
310 | stat = qla2x00_write_nvram_word_tmo(ha, 0, | 316 | wprot_old = cpu_to_le16(qla2x00_get_nvram_word(ha, ha->nvram_base)); |
317 | stat = qla2x00_write_nvram_word_tmo(ha, ha->nvram_base, | ||
311 | __constant_cpu_to_le16(0x1234), 100000); | 318 | __constant_cpu_to_le16(0x1234), 100000); |
312 | wprot = cpu_to_le16(qla2x00_get_nvram_word(ha, 0)); | 319 | wprot = cpu_to_le16(qla2x00_get_nvram_word(ha, ha->nvram_base)); |
313 | if (stat != QLA_SUCCESS || wprot != __constant_cpu_to_le16(0x1234)) { | 320 | if (stat != QLA_SUCCESS || wprot != 0x1234) { |
314 | /* Write enable. */ | 321 | /* Write enable. */ |
315 | qla2x00_nv_write(ha, NVR_DATA_OUT); | 322 | qla2x00_nv_write(ha, NVR_DATA_OUT); |
316 | qla2x00_nv_write(ha, 0); | 323 | qla2x00_nv_write(ha, 0); |
@@ -341,14 +348,22 @@ qla2x00_clear_nvram_protection(scsi_qla_host_t *ha) | |||
341 | /* Wait for NVRAM to become ready. */ | 348 | /* Wait for NVRAM to become ready. */ |
342 | WRT_REG_WORD(®->nvram, NVR_SELECT); | 349 | WRT_REG_WORD(®->nvram, NVR_SELECT); |
343 | RD_REG_WORD(®->nvram); /* PCI Posting. */ | 350 | RD_REG_WORD(®->nvram); /* PCI Posting. */ |
351 | wait_cnt = NVR_WAIT_CNT; | ||
344 | do { | 352 | do { |
353 | if (!--wait_cnt) { | ||
354 | DEBUG9_10(printk("%s(%ld): NVRAM didn't go " | ||
355 | "ready...\n", __func__, | ||
356 | ha->host_no)); | ||
357 | break; | ||
358 | } | ||
345 | NVRAM_DELAY(); | 359 | NVRAM_DELAY(); |
346 | word = RD_REG_WORD(®->nvram); | 360 | word = RD_REG_WORD(®->nvram); |
347 | } while ((word & NVR_DATA_IN) == 0); | 361 | } while ((word & NVR_DATA_IN) == 0); |
348 | 362 | ||
349 | ret = QLA_SUCCESS; | 363 | if (wait_cnt) |
364 | ret = QLA_SUCCESS; | ||
350 | } else | 365 | } else |
351 | qla2x00_write_nvram_word(ha, 0, wprot_old); | 366 | qla2x00_write_nvram_word(ha, ha->nvram_base, wprot_old); |
352 | 367 | ||
353 | return ret; | 368 | return ret; |
354 | } | 369 | } |
@@ -357,7 +372,7 @@ static void | |||
357 | qla2x00_set_nvram_protection(scsi_qla_host_t *ha, int stat) | 372 | qla2x00_set_nvram_protection(scsi_qla_host_t *ha, int stat) |
358 | { | 373 | { |
359 | struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; | 374 | struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; |
360 | uint32_t word; | 375 | uint32_t word, wait_cnt; |
361 | 376 | ||
362 | if (stat != QLA_SUCCESS) | 377 | if (stat != QLA_SUCCESS) |
363 | return; | 378 | return; |
@@ -393,7 +408,13 @@ qla2x00_set_nvram_protection(scsi_qla_host_t *ha, int stat) | |||
393 | /* Wait for NVRAM to become ready. */ | 408 | /* Wait for NVRAM to become ready. */ |
394 | WRT_REG_WORD(®->nvram, NVR_SELECT); | 409 | WRT_REG_WORD(®->nvram, NVR_SELECT); |
395 | RD_REG_WORD(®->nvram); /* PCI Posting. */ | 410 | RD_REG_WORD(®->nvram); /* PCI Posting. */ |
411 | wait_cnt = NVR_WAIT_CNT; | ||
396 | do { | 412 | do { |
413 | if (!--wait_cnt) { | ||
414 | DEBUG9_10(printk("%s(%ld): NVRAM didn't go ready...\n", | ||
415 | __func__, ha->host_no)); | ||
416 | break; | ||
417 | } | ||
397 | NVRAM_DELAY(); | 418 | NVRAM_DELAY(); |
398 | word = RD_REG_WORD(®->nvram); | 419 | word = RD_REG_WORD(®->nvram); |
399 | } while ((word & NVR_DATA_IN) == 0); | 420 | } while ((word & NVR_DATA_IN) == 0); |
@@ -500,6 +521,20 @@ qla24xx_get_flash_manufacturer(scsi_qla_host_t *ha, uint8_t *man_id, | |||
500 | ids = qla24xx_read_flash_dword(ha, flash_data_to_access_addr(0xd03ab)); | 521 | ids = qla24xx_read_flash_dword(ha, flash_data_to_access_addr(0xd03ab)); |
501 | *man_id = LSB(ids); | 522 | *man_id = LSB(ids); |
502 | *flash_id = MSB(ids); | 523 | *flash_id = MSB(ids); |
524 | |||
525 | /* Check if man_id and flash_id are valid. */ | ||
526 | if (ids != 0xDEADDEAD && (*man_id == 0 || *flash_id == 0)) { | ||
527 | /* Read information using 0x9f opcode | ||
528 | * Device ID, Mfg ID would be read in the format: | ||
529 | * <Ext Dev Info><Device ID Part2><Device ID Part 1><Mfg ID> | ||
530 | * Example: ATMEL 0x00 01 45 1F | ||
531 | * Extract MFG and Dev ID from last two bytes. | ||
532 | */ | ||
533 | ids = qla24xx_read_flash_dword(ha, | ||
534 | flash_data_to_access_addr(0xd009f)); | ||
535 | *man_id = LSB(ids); | ||
536 | *flash_id = MSB(ids); | ||
537 | } | ||
503 | } | 538 | } |
504 | 539 | ||
505 | int | 540 | int |
@@ -508,8 +543,8 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, | |||
508 | { | 543 | { |
509 | int ret; | 544 | int ret; |
510 | uint32_t liter; | 545 | uint32_t liter; |
511 | uint32_t sec_mask, rest_addr, conf_addr; | 546 | uint32_t sec_mask, rest_addr, conf_addr, sec_end_mask; |
512 | uint32_t fdata; | 547 | uint32_t fdata, findex ; |
513 | uint8_t man_id, flash_id; | 548 | uint8_t man_id, flash_id; |
514 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; | 549 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; |
515 | 550 | ||
@@ -519,6 +554,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, | |||
519 | DEBUG9(printk("%s(%ld): Flash man_id=%d flash_id=%d\n", __func__, | 554 | DEBUG9(printk("%s(%ld): Flash man_id=%d flash_id=%d\n", __func__, |
520 | ha->host_no, man_id, flash_id)); | 555 | ha->host_no, man_id, flash_id)); |
521 | 556 | ||
557 | sec_end_mask = 0; | ||
522 | conf_addr = flash_conf_to_access_addr(0x03d8); | 558 | conf_addr = flash_conf_to_access_addr(0x03d8); |
523 | switch (man_id) { | 559 | switch (man_id) { |
524 | case 0xbf: /* STT flash. */ | 560 | case 0xbf: /* STT flash. */ |
@@ -531,6 +567,12 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, | |||
531 | rest_addr = 0x3fff; | 567 | rest_addr = 0x3fff; |
532 | sec_mask = 0x3c000; | 568 | sec_mask = 0x3c000; |
533 | break; | 569 | break; |
570 | case 0x1f: // Atmel 26DF081A | ||
571 | rest_addr = 0x0fff; | ||
572 | sec_mask = 0xff000; | ||
573 | sec_end_mask = 0x003ff; | ||
574 | conf_addr = flash_conf_to_access_addr(0x0320); | ||
575 | break; | ||
534 | default: | 576 | default: |
535 | /* Default to 64 kb sector size. */ | 577 | /* Default to 64 kb sector size. */ |
536 | rest_addr = 0x3fff; | 578 | rest_addr = 0x3fff; |
@@ -545,11 +587,30 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, | |||
545 | 587 | ||
546 | /* Disable flash write-protection. */ | 588 | /* Disable flash write-protection. */ |
547 | qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0); | 589 | qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0); |
590 | /* Some flash parts need an additional zero-write to clear bits.*/ | ||
591 | qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0); | ||
548 | 592 | ||
549 | do { /* Loop once to provide quick error exit. */ | 593 | do { /* Loop once to provide quick error exit. */ |
550 | for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) { | 594 | for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) { |
595 | if (man_id == 0x1f) { | ||
596 | findex = faddr << 2; | ||
597 | fdata = findex & sec_mask; | ||
598 | } else { | ||
599 | findex = faddr; | ||
600 | fdata = (findex & sec_mask) << 2; | ||
601 | } | ||
602 | |||
551 | /* Are we at the beginning of a sector? */ | 603 | /* Are we at the beginning of a sector? */ |
552 | if ((faddr & rest_addr) == 0) { | 604 | if ((findex & rest_addr) == 0) { |
605 | /* | ||
606 | * Do sector unprotect at 4K boundry for Atmel | ||
607 | * part. | ||
608 | */ | ||
609 | if (man_id == 0x1f) | ||
610 | qla24xx_write_flash_dword(ha, | ||
611 | flash_conf_to_access_addr(0x0339), | ||
612 | (fdata & 0xff00) | ((fdata << 16) & | ||
613 | 0xff0000) | ((fdata >> 16) & 0xff)); | ||
553 | fdata = (faddr & sec_mask) << 2; | 614 | fdata = (faddr & sec_mask) << 2; |
554 | ret = qla24xx_write_flash_dword(ha, conf_addr, | 615 | ret = qla24xx_write_flash_dword(ha, conf_addr, |
555 | (fdata & 0xff00) |((fdata << 16) & | 616 | (fdata & 0xff00) |((fdata << 16) & |
@@ -570,6 +631,14 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, | |||
570 | ha->host_no, faddr, *dwptr)); | 631 | ha->host_no, faddr, *dwptr)); |
571 | break; | 632 | break; |
572 | } | 633 | } |
634 | |||
635 | /* Do sector protect at 4K boundry for Atmel part. */ | ||
636 | if (man_id == 0x1f && | ||
637 | ((faddr & sec_end_mask) == 0x3ff)) | ||
638 | qla24xx_write_flash_dword(ha, | ||
639 | flash_conf_to_access_addr(0x0336), | ||
640 | (fdata & 0xff00) | ((fdata << 16) & | ||
641 | 0xff0000) | ((fdata >> 16) & 0xff)); | ||
573 | } | 642 | } |
574 | } while (0); | 643 | } while (0); |
575 | 644 | ||