Commit db2b6d05 authored by Christoph Hellwig's avatar Christoph Hellwig

[PATCH] qla1280: cleanup firmware loading, add pio-based loading

The ISP1040 needs to load firmware by PIO, and while we're at it clean
the convoluted mess of firmware loading up by splitting it into
managable subroutines.
Signed-off-by: default avatarJes Sorensen <jes@wildopensource.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 94d4911b
...@@ -509,9 +509,7 @@ static int qla1280_setup(char *s) __init; ...@@ -509,9 +509,7 @@ static int qla1280_setup(char *s) __init;
/* /*
* QLogic ISP1280 Hardware Support Function Prototypes. * QLogic ISP1280 Hardware Support Function Prototypes.
*/ */
static int qla1280_isp_firmware(struct scsi_qla_host *); static int qla1280_load_firmware(struct scsi_qla_host *);
static int qla1280_chip_diag(struct scsi_qla_host *);
static int qla1280_setup_chip(struct scsi_qla_host *);
static int qla1280_init_rings(struct scsi_qla_host *); static int qla1280_init_rings(struct scsi_qla_host *);
static int qla1280_nvram_config(struct scsi_qla_host *); static int qla1280_nvram_config(struct scsi_qla_host *);
static int qla1280_mailbox_command(struct scsi_qla_host *, static int qla1280_mailbox_command(struct scsi_qla_host *,
...@@ -1802,17 +1800,8 @@ qla1280_initialize_adapter(struct scsi_qla_host *ha) ...@@ -1802,17 +1800,8 @@ qla1280_initialize_adapter(struct scsi_qla_host *ha)
*/ */
spin_lock_irqsave(HOST_LOCK, flags); spin_lock_irqsave(HOST_LOCK, flags);
#endif #endif
/* If firmware needs to be loaded */
if (qla1280_isp_firmware(ha)) {
if (!(status = qla1280_chip_diag(ha))) {
status = qla1280_setup_chip(ha);
}
} else {
printk(KERN_ERR "scsi(%li): isp_firmware() failed!\n",
ha->host_no);
status = 1;
}
status = qla1280_load_firmware(ha);
if (status) { if (status) {
printk(KERN_ERR "scsi(%li): initialize: pci probe failed!\n", printk(KERN_ERR "scsi(%li): initialize: pci probe failed!\n",
ha->host_no); ha->host_no);
...@@ -1945,13 +1934,13 @@ qla1280_chip_diag(struct scsi_qla_host *ha) ...@@ -1945,13 +1934,13 @@ qla1280_chip_diag(struct scsi_qla_host *ha)
int status = 0; int status = 0;
int cnt; int cnt;
uint16_t data; uint16_t data;
dprintk(3, "qla1280_chip_diag: testing device at 0x%p \n", &reg->id_l); dprintk(3, "qla1280_chip_diag: testing device at 0x%p \n", &reg->id_l);
dprintk(1, "scsi(%ld): Verifying chip\n", ha->host_no); dprintk(1, "scsi(%ld): Verifying chip\n", ha->host_no);
/* Soft reset chip and wait for it to finish. */ /* Soft reset chip and wait for it to finish. */
WRT_REG_WORD(&reg->ictrl, ISP_RESET); WRT_REG_WORD(&reg->ictrl, ISP_RESET);
/* /*
* We can't do a traditional PCI write flush here by reading * We can't do a traditional PCI write flush here by reading
* back the register. The card will not respond once the reset * back the register. The card will not respond once the reset
...@@ -1969,27 +1958,22 @@ qla1280_chip_diag(struct scsi_qla_host *ha) ...@@ -1969,27 +1958,22 @@ qla1280_chip_diag(struct scsi_qla_host *ha)
data = RD_REG_WORD(&reg->ictrl); data = RD_REG_WORD(&reg->ictrl);
} }
if (cnt) { if (!cnt)
goto fail;
/* Reset register cleared by chip reset. */ /* Reset register cleared by chip reset. */
dprintk(3, "qla1280_chip_diag: reset register cleared by " dprintk(3, "qla1280_chip_diag: reset register cleared by chip reset\n");
"chip reset\n");
WRT_REG_WORD(&reg->cfg_1, 0); WRT_REG_WORD(&reg->cfg_1, 0);
/* Reset RISC and disable BIOS which /* Reset RISC and disable BIOS which
allows RISC to execute out of RAM. */ allows RISC to execute out of RAM. */
#if 0
WRT_REG_WORD(&reg->host_cmd, HC_RESET_RISC);
RD_REG_WORD(&reg->id_l); /* Flush PCI write */
WRT_REG_WORD(&reg->host_cmd, HC_RELEASE_RISC);
RD_REG_WORD(&reg->id_l); /* Flush PCI write */
WRT_REG_WORD(&reg->host_cmd, HC_DISABLE_BIOS);
#else
WRT_REG_WORD(&reg->host_cmd, HC_RESET_RISC | WRT_REG_WORD(&reg->host_cmd, HC_RESET_RISC |
HC_RELEASE_RISC | HC_DISABLE_BIOS); HC_RELEASE_RISC | HC_DISABLE_BIOS);
#endif
RD_REG_WORD(&reg->id_l); /* Flush PCI write */ RD_REG_WORD(&reg->id_l); /* Flush PCI write */
data = qla1280_debounce_register(&reg->mailbox0); data = qla1280_debounce_register(&reg->mailbox0);
/* /*
* I *LOVE* this code! * I *LOVE* this code!
*/ */
...@@ -1998,10 +1982,11 @@ qla1280_chip_diag(struct scsi_qla_host *ha) ...@@ -1998,10 +1982,11 @@ qla1280_chip_diag(struct scsi_qla_host *ha)
data = RD_REG_WORD(&reg->mailbox0); data = RD_REG_WORD(&reg->mailbox0);
} }
if (cnt) { if (!cnt)
goto fail;
/* Check product ID of chip */ /* Check product ID of chip */
dprintk(3, "qla1280_chip_diag: Checking product " dprintk(3, "qla1280_chip_diag: Checking product ID of chip\n");
"ID of chip\n");
if (RD_REG_WORD(&reg->mailbox1) != PROD_ID_1 || if (RD_REG_WORD(&reg->mailbox1) != PROD_ID_1 ||
(RD_REG_WORD(&reg->mailbox2) != PROD_ID_2 && (RD_REG_WORD(&reg->mailbox2) != PROD_ID_2 &&
...@@ -2014,15 +1999,15 @@ qla1280_chip_diag(struct scsi_qla_host *ha) ...@@ -2014,15 +1999,15 @@ qla1280_chip_diag(struct scsi_qla_host *ha)
RD_REG_WORD(&reg->mailbox2), RD_REG_WORD(&reg->mailbox2),
RD_REG_WORD(&reg->mailbox3), RD_REG_WORD(&reg->mailbox3),
RD_REG_WORD(&reg->mailbox4)); RD_REG_WORD(&reg->mailbox4));
status = 1; goto fail;
} else { }
/* /*
* Enable ints early!!! * Enable ints early!!!
*/ */
qla1280_enable_intrs(ha); qla1280_enable_intrs(ha);
dprintk(1, "qla1280_chip_diag: Checking " dprintk(1, "qla1280_chip_diag: Checking mailboxes of chip\n");
"mailboxes of chip\n");
/* Wrap Incoming Mailboxes Test. */ /* Wrap Incoming Mailboxes Test. */
mb[0] = MBC_MAILBOX_REGISTER_TEST; mb[0] = MBC_MAILBOX_REGISTER_TEST;
mb[1] = 0xAAAA; mb[1] = 0xAAAA;
...@@ -2032,82 +2017,79 @@ qla1280_chip_diag(struct scsi_qla_host *ha) ...@@ -2032,82 +2017,79 @@ qla1280_chip_diag(struct scsi_qla_host *ha)
mb[5] = 0xA5A5; mb[5] = 0xA5A5;
mb[6] = 0x5A5A; mb[6] = 0x5A5A;
mb[7] = 0x2525; mb[7] = 0x2525;
if (!(status = qla1280_mailbox_command(ha,
0xff, status = qla1280_mailbox_command(ha, 0xff, mb);
&mb if (status)
[0]))) { goto fail;
if (mb[1] != 0xAAAA ||
mb[2] != 0x5555 || if (mb[1] != 0xAAAA || mb[2] != 0x5555 || mb[3] != 0xAA55 ||
mb[3] != 0xAA55 || mb[4] != 0x55AA || mb[5] != 0xA5A5 || mb[6] != 0x5A5A ||
mb[4] != 0x55AA ||
mb[5] != 0xA5A5 ||
mb[6] != 0x5A5A ||
mb[7] != 0x2525) { mb[7] != 0x2525) {
status = 1; printk(KERN_INFO "qla1280: Failed mbox check\n");
printk(KERN_INFO "qla1280: " goto fail;
"Failed mbox check\n");
} }
}
}
} else
status = 1;
} else
status = 1;
if (status)
dprintk(2, "qla1280_chip_diag: **** FAILED ****\n");
else
dprintk(3, "qla1280_chip_diag: exiting normally\n"); dprintk(3, "qla1280_chip_diag: exiting normally\n");
return 0;
fail:
dprintk(2, "qla1280_chip_diag: **** FAILED ****\n");
return status; return status;
} }
/*
* Setup chip
* Load and start RISC firmware.
*
* Input:
* ha = adapter block pointer.
*
* Returns:
* 0 = success.
*/
#define DUMP_IT_BACK 0 /* for debug of RISC loading */
static int static int
qla1280_setup_chip(struct scsi_qla_host *ha) qla1280_load_firmware_pio(struct scsi_qla_host *ha)
{ {
int status = 0; uint16_t risc_address, *risc_code_address, risc_code_size;
uint16_t risc_address; uint16_t mb[MAILBOX_REGISTER_COUNT], i;
uint16_t *risc_code_address; int err;
int risc_code_size;
uint16_t mb[MAILBOX_REGISTER_COUNT];
uint16_t cnt;
int num, i;
#if DUMP_IT_BACK
uint8_t *sp;
uint8_t *tbuf;
dma_addr_t p_tbuf;
#endif
ENTER("qla1280_setup_chip"); /* Load RISC code. */
risc_address = *ql1280_board_tbl[ha->devnum].fwstart;
risc_code_address = ql1280_board_tbl[ha->devnum].fwcode;
risc_code_size = *ql1280_board_tbl[ha->devnum].fwlen;
dprintk(1, "scsi(%ld): Setup chip\n", ha->host_no); for (i = 0; i < risc_code_size; i++) {
mb[0] = MBC_WRITE_RAM_WORD;
mb[1] = risc_address + i;
mb[2] = risc_code_address[i];
err = qla1280_mailbox_command(ha, BIT_0 | BIT_1 | BIT_2, mb);
if (err) {
printk(KERN_ERR "scsi(%li): Failed to load firmware\n",
ha->host_no);
return err;
}
}
return 0;
}
#define DUMP_IT_BACK 0 /* for debug of RISC loading */
static int
qla1280_load_firmware_dma(struct scsi_qla_host *ha)
{
uint16_t risc_address, *risc_code_address, risc_code_size;
uint16_t mb[MAILBOX_REGISTER_COUNT], cnt;
int err = 0, num, i;
#if DUMP_IT_BACK #if DUMP_IT_BACK
/* get consistent memory allocated for setup_chip */ uint8_t *sp, *tbuf;
dma_addr_t p_tbuf;
tbuf = pci_alloc_consistent(ha->pdev, 8000, &p_tbuf); tbuf = pci_alloc_consistent(ha->pdev, 8000, &p_tbuf);
if (!tbuf)
return -ENOMEM;
#endif #endif
/* Load RISC code. */ /* Load RISC code. */
risc_address = *ql1280_board_tbl[ha->devnum].fwstart; risc_address = *ql1280_board_tbl[ha->devnum].fwstart;
risc_code_address = ql1280_board_tbl[ha->devnum].fwcode; risc_code_address = ql1280_board_tbl[ha->devnum].fwcode;
risc_code_size = (int) *ql1280_board_tbl[ha->devnum].fwlen; risc_code_size = *ql1280_board_tbl[ha->devnum].fwlen;
dprintk(1, "qla1280_setup_chip: DMA RISC code (%i) words\n", dprintk(1, "%s: DMA RISC code (%i) words\n",
risc_code_size); __FUNCTION__, risc_code_size);
num = 0; num = 0;
while (risc_code_size > 0 && !status) { while (risc_code_size > 0) {
int warn __attribute__((unused)) = 0; int warn __attribute__((unused)) = 0;
cnt = 2000 >> 1; cnt = 2000 >> 1;
...@@ -2129,15 +2111,16 @@ qla1280_setup_chip(struct scsi_qla_host *ha) ...@@ -2129,15 +2111,16 @@ qla1280_setup_chip(struct scsi_qla_host *ha)
mb[2] = (ha->request_dma >> 16) & 0xffff; mb[2] = (ha->request_dma >> 16) & 0xffff;
mb[7] = pci_dma_hi32(ha->request_dma) & 0xffff; mb[7] = pci_dma_hi32(ha->request_dma) & 0xffff;
mb[6] = pci_dma_hi32(ha->request_dma) >> 16; mb[6] = pci_dma_hi32(ha->request_dma) >> 16;
dprintk(2, "qla1280_setup_chip: op=%d 0x%p = 0x%4x,0x%4x," dprintk(2, "%s: op=%d 0x%p = 0x%4x,0x%4x,0x%4x,0x%4x\n",
"0x%4x,0x%4x\n", mb[0], (void *)(long)ha->request_dma, __FUNCTION__, mb[0],
(void *)(long)ha->request_dma,
mb[6], mb[7], mb[2], mb[3]); mb[6], mb[7], mb[2], mb[3]);
if ((status = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | err = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | BIT_2 |
BIT_2 | BIT_1 | BIT_0, BIT_1 | BIT_0, mb);
&mb[0]))) { if (err) {
printk(KERN_ERR "scsi(%li): Failed to load partial " printk(KERN_ERR "scsi(%li): Failed to load partial "
"segment of f\n", ha->host_no); "segment of f\n", ha->host_no);
break; goto out;
} }
#if DUMP_IT_BACK #if DUMP_IT_BACK
...@@ -2149,22 +2132,22 @@ qla1280_setup_chip(struct scsi_qla_host *ha) ...@@ -2149,22 +2132,22 @@ qla1280_setup_chip(struct scsi_qla_host *ha)
mb[7] = pci_dma_hi32(p_tbuf) & 0xffff; mb[7] = pci_dma_hi32(p_tbuf) & 0xffff;
mb[6] = pci_dma_hi32(p_tbuf) >> 16; mb[6] = pci_dma_hi32(p_tbuf) >> 16;
if ((status = qla1280_mailbox_command(ha, err = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | BIT_2 |
BIT_4 | BIT_3 | BIT_2 | BIT_1 | BIT_0, mb);
BIT_1 | BIT_0, if (err) {
&mb[0]))) {
printk(KERN_ERR printk(KERN_ERR
"Failed to dump partial segment of f/w\n"); "Failed to dump partial segment of f/w\n");
break; goto out;
} }
sp = (uint8_t *)ha->request_ring; sp = (uint8_t *)ha->request_ring;
for (i = 0; i < (cnt << 1); i++) { for (i = 0; i < (cnt << 1); i++) {
if (tbuf[i] != sp[i] && warn++ < 10) { if (tbuf[i] != sp[i] && warn++ < 10) {
printk(KERN_ERR "qla1280_setup_chip: FW " printk(KERN_ERR "%s: FW compare error @ "
"compare error @ byte(0x%x) loop#=%x\n", "byte(0x%x) loop#=%x\n",
i, num); __FUNCTION__, i, num);
printk(KERN_ERR "setup_chip: FWbyte=%x " printk(KERN_ERR "%s: FWbyte=%x "
"FWfromChip=%x\n", sp[i], tbuf[i]); "FWfromChip=%x\n",
__FUNCTION__, sp[i], tbuf[i]);
/*break; */ /*break; */
} }
} }
...@@ -2175,37 +2158,69 @@ qla1280_setup_chip(struct scsi_qla_host *ha) ...@@ -2175,37 +2158,69 @@ qla1280_setup_chip(struct scsi_qla_host *ha)
num++; num++;
} }
out:
#if DUMP_IT_BACK
pci_free_consistent(ha->pdev, 8000, tbuf, p_tbuf);
#endif
return err;
}
static int
qla1280_start_firmware(struct scsi_qla_host *ha)
{
uint16_t mb[MAILBOX_REGISTER_COUNT];
int err;
dprintk(1, "%s: Verifying checksum of loaded RISC code.\n",
__FUNCTION__);
/* Verify checksum of loaded RISC code. */ /* Verify checksum of loaded RISC code. */
if (!status) {
dprintk(1, "qla1280_setup_chip: Verifying checksum of "
"loaded RISC code.\n");
mb[0] = MBC_VERIFY_CHECKSUM; mb[0] = MBC_VERIFY_CHECKSUM;
/* mb[1] = ql12_risc_code_addr01; */ /* mb[1] = ql12_risc_code_addr01; */
mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; mb[1] = *ql1280_board_tbl[ha->devnum].fwstart;
err = qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb);
if (err) {
printk(KERN_ERR "scsi(%li): Failed checksum\n", ha->host_no);
return err;
}
if (!(status =
qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]))) {
/* Start firmware execution. */ /* Start firmware execution. */
dprintk(1, dprintk(1, "%s: start firmware running.\n", __FUNCTION__);
"qla1280_setup_chip: start firmware running.\n");
mb[0] = MBC_EXECUTE_FIRMWARE; mb[0] = MBC_EXECUTE_FIRMWARE;
mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; mb[1] = *ql1280_board_tbl[ha->devnum].fwstart;
qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); err = qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]);
} else if (err) {
printk(KERN_ERR "scsi(%li): qla1280_setup_chip: " printk(KERN_ERR "scsi(%li): Failed to start firmware\n",
"Failed checksum\n", ha->host_no); ha->host_no);
} }
#if DUMP_IT_BACK return err;
/* free consistent memory allocated for setup_chip */ }
pci_free_consistent(ha->pdev, 8000, tbuf, p_tbuf);
#endif
if (status) static int
dprintk(2, "qla1280_setup_chip: **** FAILED ****\n"); qla1280_load_firmware(struct scsi_qla_host *ha)
{
int err = -ENODEV;
LEAVE("qla1280_setup_chip"); /* If firmware needs to be loaded */
return status; if (!qla1280_isp_firmware(ha)) {
printk(KERN_ERR "scsi(%li): isp_firmware() failed!\n",
ha->host_no);
goto out;
}
err = qla1280_chip_diag(ha);
if (err)
goto out;
if (IS_ISP1040(ha))
err = qla1280_load_firmware_pio(ha);
else
err = qla1280_load_firmware_dma(ha);
if (err)
goto out;
err = qla1280_start_firmware(ha);
out:
return err;
} }
/* /*
...@@ -4227,6 +4242,7 @@ qla1280_error_entry(struct scsi_qla_host *ha, struct response *pkt, ...@@ -4227,6 +4242,7 @@ qla1280_error_entry(struct scsi_qla_host *ha, struct response *pkt,
static int static int
qla1280_abort_isp(struct scsi_qla_host *ha) qla1280_abort_isp(struct scsi_qla_host *ha)
{ {
struct device_reg *reg = ha->iobase;
struct srb *sp; struct srb *sp;
int status = 0; int status = 0;
int cnt; int cnt;
...@@ -4234,8 +4250,9 @@ qla1280_abort_isp(struct scsi_qla_host *ha) ...@@ -4234,8 +4250,9 @@ qla1280_abort_isp(struct scsi_qla_host *ha)
ENTER("qla1280_abort_isp"); ENTER("qla1280_abort_isp");
if (!ha->flags.abort_isp_active && ha->flags.online) { if (ha->flags.abort_isp_active || !ha->flags.online)
struct device_reg *reg = ha->iobase; goto out;
ha->flags.abort_isp_active = 1; ha->flags.abort_isp_active = 1;
/* Disable ISP interrupts. */ /* Disable ISP interrupts. */
...@@ -4263,40 +4280,23 @@ qla1280_abort_isp(struct scsi_qla_host *ha) ...@@ -4263,40 +4280,23 @@ qla1280_abort_isp(struct scsi_qla_host *ha)
} }
} }
/* If firmware needs to be loaded */ status = qla1280_load_firmware(ha);
if (qla1280_isp_firmware (ha)) { if (status)
if (!(status = qla1280_chip_diag(ha))) goto out;
status = qla1280_setup_chip(ha);
}
if (!status) {
/* Setup adapter based on NVRAM parameters. */ /* Setup adapter based on NVRAM parameters. */
qla1280_nvram_config (ha); qla1280_nvram_config (ha);
if (!(status = qla1280_init_rings(ha))) { status = qla1280_init_rings(ha);
if (status)
goto out;
/* Issue SCSI reset. */ /* Issue SCSI reset. */
for (bus = 0; bus < ha->ports; bus++) { for (bus = 0; bus < ha->ports; bus++)
qla1280_bus_reset(ha, bus); qla1280_bus_reset(ha, bus);
}
/*
* qla1280_bus_reset() will do the marker
* dance - no reason to repeat here!
*/
#if 0
/* Issue marker command. */
ha->flags.reset_marker = 0;
for (bus = 0; bus < ha->ports; bus++) {
ha->bus_settings[bus].
reset_marker = 0;
qla1280_marker(ha, bus, 0, 0,
MK_SYNC_ALL);
}
#endif
ha->flags.abort_isp_active = 0;
}
}
}
ha->flags.abort_isp_active = 0;
out:
if (status) { if (status) {
printk(KERN_WARNING printk(KERN_WARNING
"qla1280: ISP error recovery failed, board disabled"); "qla1280: ISP error recovery failed, board disabled");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment