mirror of
https://github.com/Fohdeesha/lab-docu.git
synced 2024-11-25 10:45:10 +01:00
2681 lines
75 KiB
C
2681 lines
75 KiB
C
/***************************************************************************
|
|
* *
|
|
* Copyright 2012 LSI Corporation. All rights reserved. *
|
|
* *
|
|
* This file is confidential and a trade secret of LSI Corporation. The *
|
|
* receipt of or possession of this file does not convey any rights to *
|
|
* reproduce or disclose its contents or to manufacture, use, or sell *
|
|
* anything it may describe, in whole, or in part, without the specific *
|
|
* written consent of LSI Corporation. *
|
|
* *
|
|
***************************************************************************
|
|
*/
|
|
/*
|
|
* mpt -- simple driver for MPT adapters (FC, SCSI, and SAS/SATA)
|
|
*
|
|
* Written by Stephen F. Shirron, August 9, 2005
|
|
*/
|
|
|
|
|
|
#ifdef DISABLE_TIMEOUTS
|
|
static time_t local_time = 0;
|
|
#define time(x) (local_time)
|
|
#endif
|
|
|
|
|
|
#define NUM_REPLIES 7
|
|
#define REPLY_FREE_SIZE 8
|
|
#define REPLY_POST_SIZE 16
|
|
#define COMMAND_CONTEXT 0x111111
|
|
#define PASS_THRU_CONTEXT 0x555555
|
|
|
|
|
|
#define mpi1 (adap->mpt_version < MPI2_VERSION_02_00)
|
|
#define mpi2 (adap->mpt_version >= MPI2_VERSION_02_00)
|
|
#define mpi20 ((adap->mpt_version >= MPI2_VERSION_02_00) && (adap->mpt_version < MPI2_VERSION_02_05))
|
|
#define mpi25 (adap->mpt_version >= MPI2_VERSION_02_05)
|
|
|
|
|
|
typedef struct mpt_io_rep
|
|
{
|
|
union
|
|
{
|
|
SCSIIOReply_t default_reply;
|
|
U32 reply[32];
|
|
} mf;
|
|
} mpt_io_rep_t;
|
|
|
|
|
|
typedef struct mpt_shared
|
|
{
|
|
mpt_io_rep_t replies[NUM_REPLIES];
|
|
U32 message[32];
|
|
U32 free_queue[REPLY_FREE_SIZE];
|
|
MPI2_DEFAULT_REPLY_DESCRIPTOR
|
|
post_queue[REPLY_POST_SIZE];
|
|
U16 data[64];
|
|
U32 config[256];
|
|
U8 scratch[1024*1024 + 1024]; // 1MB + 1K - big enough for 1MB payload plus request/response
|
|
U32 hrsm_value;
|
|
} mpt_shared_t;
|
|
|
|
|
|
typedef struct mpt_adap
|
|
{
|
|
MPT_PORT *port;
|
|
HANDLE partner_adap;
|
|
char *name;
|
|
U16 vendor_id;
|
|
U16 device_id;
|
|
U8 revision_id;
|
|
U8 segment_number;
|
|
U8 bus_number;
|
|
U8 device_function;
|
|
int mpt_version;
|
|
int hrsm_capable;
|
|
U32 hrsm_value;
|
|
U32 msg_context;
|
|
int restart_needed;
|
|
int port_enable_needed;
|
|
int config_active;
|
|
int command_active;
|
|
mpt_shared_t *shared;
|
|
mpt_bus_addr_t shared_ba;
|
|
int message_size;
|
|
int reply_depth;
|
|
int credits;
|
|
int port_count;
|
|
int block_size;
|
|
int port_type;
|
|
int host_id;
|
|
U32 interrupt_mask;
|
|
int max_targets;
|
|
int bus_reset_needed;
|
|
U32 capabilities[16];
|
|
int ioc_online;
|
|
int port_online;
|
|
int bootloader;
|
|
int loaddevice;
|
|
U8 *fw_image;
|
|
int fw_image_size;
|
|
int fw_image_asked;
|
|
U32 mem_size;
|
|
U32 diagmem_size;
|
|
#if DOS
|
|
U32 io_addr;
|
|
U32 mem_addr;
|
|
U32 mem_virt;
|
|
U32 diagmem_addr;
|
|
U32 diagmem_virt;
|
|
CONTIGUOUS_MEMORY shared_contig_mem;
|
|
#endif
|
|
#if EFI
|
|
EFI_HANDLE handle;
|
|
EFI_PCI_IO_PROTOCOL *pci_io;
|
|
void *buffer_mapping;
|
|
int disconnected;
|
|
#endif
|
|
int io;
|
|
int mem;
|
|
int diagmem;
|
|
int free_index;
|
|
int post_index;
|
|
} mpt_adap_t;
|
|
|
|
|
|
#define rl(x) mpt_read32(adap, MPI_##x##_OFFSET, adap->mem)
|
|
#define wl(x,y) mpt_write32(adap, MPI_##x##_OFFSET, y, adap->mem)
|
|
#define rl2(x) mpt_read32(adap, MPI2_##x##_OFFSET, adap->mem)
|
|
#define wl2(x,y) mpt_write32(adap, MPI2_##x##_OFFSET, y, adap->mem)
|
|
#define rlio(x) mpt_read32(adap, MPI_##x##_OFFSET, adap->io)
|
|
#define wlio(x,y) mpt_write32(adap, MPI_##x##_OFFSET, y, adap->io)
|
|
#define rldiag(x,y) wl(TEST_BASE_ADDRESS, x & ~mask); y = mpt_read32(adap, x & mask, adap->diagmem)
|
|
#define wldiag(x,y) wl(TEST_BASE_ADDRESS, x & ~mask); mpt_write32(adap, x & mask, y, adap->diagmem)
|
|
U32 mpt_read32(mpt_adap_t *adap, int offset, int bar)
|
|
{
|
|
U32 data;
|
|
|
|
#if DOS
|
|
if (bar == adap->mem)
|
|
data = *(U32 *)(adap->mem_virt + offset);
|
|
else if (bar == adap->diagmem)
|
|
data = *(U32 *)(adap->diagmem_virt + offset);
|
|
else
|
|
data = inpd(adap->io_addr + offset);
|
|
#endif
|
|
#if EFI
|
|
if (bar == adap->mem || bar == adap->diagmem)
|
|
adap->pci_io->Mem.Read(adap->pci_io, EfiPciIoWidthUint32, (char)bar, offset, 1, &data);
|
|
else
|
|
adap->pci_io->Io.Read(adap->pci_io, EfiPciIoWidthUint32, (char)bar, offset, 1, &data);
|
|
#endif
|
|
|
|
return data;
|
|
}
|
|
void mpt_write32(mpt_adap_t *adap, int offset, U32 data, int bar)
|
|
{
|
|
#if DOS
|
|
if (bar == adap->mem)
|
|
*(U32 *)(adap->mem_virt + offset) = data;
|
|
else if (bar == adap->diagmem)
|
|
*(U32 *)(adap->diagmem_virt + offset) = data;
|
|
else
|
|
outpd(adap->io_addr + offset, data);
|
|
#endif
|
|
#if EFI
|
|
if (bar == adap->mem || bar == adap->diagmem)
|
|
adap->pci_io->Mem.Write(adap->pci_io, EfiPciIoWidthUint32, (char)bar, offset, 1, &data);
|
|
else
|
|
adap->pci_io->Io.Write(adap->pci_io, EfiPciIoWidthUint32, (char)bar, offset, 1, &data);
|
|
#endif
|
|
}
|
|
void mpt_write8(mpt_adap_t *adap, int offset, U8 data)
|
|
{
|
|
#if DOS
|
|
*(U8 *)(adap->diagmem_virt + offset) = data;
|
|
#endif
|
|
#if EFI
|
|
adap->pci_io->Mem.Write(adap->pci_io, EfiPciIoWidthUint8, (char)adap->diagmem, offset, 1, &data);
|
|
#endif
|
|
}
|
|
#define MPI_DEBUG_OFFSET 0x18
|
|
#define MPI_FC909_BUG_OFFSET 0x90
|
|
#define MPI_SAS1078_RESET_OFFSET 0x10FC
|
|
|
|
|
|
int mpt_adjust_delay(mpt_adap_t *adap, int n);
|
|
void mpt_delay(mpt_adap_t *adap, int n);
|
|
int mpt_get_doorbell(mpt_adap_t *adap);
|
|
int mpt_get_state(mpt_adap_t *adap);
|
|
int mpt_verify_enabled(mpt_adap_t *adap);
|
|
int mpt_verify_ready(mpt_adap_t *adap);
|
|
int mpt_verify_operational(mpt_adap_t *adap);
|
|
int mpt_wait_for_ready(mpt_adap_t *adap);
|
|
int mpt_restart(mpt_adap_t *adap);
|
|
int mpt_stop(mpt_adap_t *adap, int wait);
|
|
int mpt_start(mpt_adap_t *adap);
|
|
int mpt_port_online(mpt_adap_t *adap);
|
|
int mpt_wait_for_doorbell(mpt_adap_t *adap, time_t limit);
|
|
int mpt_wait_for_response(mpt_adap_t *adap, time_t limit);
|
|
int mpt_send_message(mpt_adap_t *adap, int length, time_t limit);
|
|
int mpt_receive_data(mpt_adap_t *adap, int length, time_t limit);
|
|
int mpt_issue_command_and_wait(mpt_adap_t *adap, int wait);
|
|
int mpt_issue_config_and_wait(mpt_adap_t *adap, int wait);
|
|
int mpt_issue_ioc_facts(mpt_adap_t *adap);
|
|
int mpt2_issue_ioc_facts(mpt_adap_t *adap);
|
|
int mpt_issue_ioc_init(mpt_adap_t *adap);
|
|
int mpt2_issue_ioc_init(mpt_adap_t *adap);
|
|
int mpt_initialize(mpt_adap_t *adap);
|
|
int mpt_issue_port_facts(mpt_adap_t *adap, int port);
|
|
int mpt2_issue_port_facts(mpt_adap_t *adap, int port);
|
|
int mpt_issue_port_enable(mpt_adap_t *adap, int port);
|
|
int mpt2_issue_port_enable(mpt_adap_t *adap, int port);
|
|
int mpt_issue_event_notification(mpt_adap_t *adap);
|
|
int mpt2_issue_event_notification(mpt_adap_t *adap);
|
|
int mpt_watchdog(mpt_adap_t *adap);
|
|
int mpt_init_device_capabilities(mpt_adap_t *adap);
|
|
int mpt_set_device_capabilities(mpt_adap_t *adap, int targ);
|
|
int mpt_set_on_bus_timer(mpt_adap_t *adap, int timeout);
|
|
int mpt_get_config_page(mpt_adap_t *adap, int type, int number, int address);
|
|
int mpt_set_config_page(mpt_adap_t *adap, int type, int number, int address);
|
|
int mpt_do_config_action(mpt_adap_t *adap, int action, int type, int number, int address, int length);
|
|
void mpt_bus_reset(mpt_adap_t *adap);
|
|
void mpt_interrupt(mpt_adap_t *adap);
|
|
void mpt2_interrupt(mpt_adap_t *adap);
|
|
int mpt_handle_reply(mpt_adap_t *adap, MPIDefaultReply_t *reply, U32 reply_ba);
|
|
void mpt2_handle_scsi_io_success(mpt_adap_t *adap, Mpi2DefaultReplyDescriptor_t *reply_desc);
|
|
void mpt2_handle_address_reply(mpt_adap_t *adap, Mpi2DefaultReplyDescriptor_t *reply_desc);
|
|
int mpt_fwdownloadboot(mpt_adap_t *adap);
|
|
int mpt_directdownload(mpt_adap_t *adap);
|
|
|
|
|
|
int
|
|
mpt_adjust_delay(mpt_adap_t *adap, int n)
|
|
{
|
|
if (adap->revision_id == 0xff)
|
|
return n * 10;
|
|
|
|
return n;
|
|
}
|
|
|
|
|
|
void
|
|
mpt_delay(mpt_adap_t *adap, int n)
|
|
{
|
|
#if DOS
|
|
int i;
|
|
|
|
for (i = 0; i < mpt_adjust_delay(adap, n); i++)
|
|
{
|
|
PciReadConfigWord(adap->bus_number, adap->device_function, PCI_CONFIG_DEVICE_ID);
|
|
}
|
|
#endif
|
|
#if EFI
|
|
udelay(mpt_adjust_delay(adap, n));
|
|
#endif
|
|
}
|
|
|
|
|
|
int
|
|
mpt_get_doorbell(mpt_adap_t *adap)
|
|
{
|
|
return rl(DOORBELL);
|
|
}
|
|
|
|
|
|
int
|
|
mpt_get_state(mpt_adap_t *adap)
|
|
{
|
|
return rl(DOORBELL) & MPI_IOC_STATE_MASK;
|
|
}
|
|
|
|
|
|
int
|
|
mpt_verify_enabled(mpt_adap_t *adap)
|
|
{
|
|
if (rl(DIAGNOSTIC) & MPI_DIAG_DISABLE_ARM)
|
|
if (mpt_stop(adap, TRUE))
|
|
return mpt_restart(adap);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int
|
|
mpt_verify_ready(mpt_adap_t *adap)
|
|
{
|
|
if (adap->restart_needed == TRUE)
|
|
return 0;
|
|
|
|
if ((rl(DOORBELL) & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_READY)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int
|
|
mpt_verify_operational(mpt_adap_t *adap)
|
|
{
|
|
if (adap->restart_needed == TRUE)
|
|
return 0;
|
|
|
|
if ((rl(DOORBELL) & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int
|
|
mpt_wait_for_ready(mpt_adap_t *adap)
|
|
{
|
|
U32 doorbell;
|
|
U32 diagnostic;
|
|
int state;
|
|
time_t limit = time(NULL) + mpt_adjust_delay(adap, 50);
|
|
|
|
while (time(NULL) < limit)
|
|
{
|
|
doorbell = rl(DOORBELL);
|
|
state = doorbell & MPI_IOC_STATE_MASK;
|
|
if (state == MPI_IOC_STATE_FAULT)
|
|
{
|
|
printf("\n%s: MPT Firmware Fault, code %04x\n",
|
|
adap->name, doorbell & MPI_DOORBELL_DATA_MASK);
|
|
if (wFlag)
|
|
fprintf(logFile, "%s: MPT Firmware Fault, code %04x\n",
|
|
adap->name, doorbell & MPI_DOORBELL_DATA_MASK);
|
|
|
|
printf("\nDo you want to continue? [Yes or No, default is No] ");
|
|
|
|
if (getYesNoAnswer(0) != 1)
|
|
break;
|
|
|
|
printf("\n");
|
|
|
|
adap->restart_needed = TRUE;
|
|
return 0;
|
|
}
|
|
if (state == MPI_IOC_STATE_READY)
|
|
{
|
|
adap->restart_needed = FALSE;
|
|
return 1;
|
|
}
|
|
diagnostic = rl(DIAGNOSTIC);
|
|
if (diagnostic & MPI_DIAG_FLASH_BAD_SIG)
|
|
{
|
|
if (adap->fw_image == NULL)
|
|
{
|
|
printf("\n%s: FLASH does not contain a valid image\n", adap->name);
|
|
if (wFlag)
|
|
fprintf(logFile, "%s: FLASH does not contain a valid image\n",
|
|
adap->name);
|
|
}
|
|
adap->restart_needed = TRUE;
|
|
return 0;
|
|
}
|
|
if (diagnostic & MPI_DIAG_DISABLE_ARM)
|
|
{
|
|
printf("\n%s: IOP ARM is disabled\n", adap->name);
|
|
if (wFlag)
|
|
fprintf(logFile, "%s: IOP ARM is disabled\n",
|
|
adap->name);
|
|
adap->restart_needed = TRUE;
|
|
return 0;
|
|
}
|
|
DELAY(1);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* mpt_restart - completely restart the IOC and any outstanding commands.
|
|
*/
|
|
int
|
|
mpt_restart(mpt_adap_t *adap)
|
|
{
|
|
int targ;
|
|
|
|
// printf("mpt_restart called\n");
|
|
|
|
if (!mpt_verify_ready(adap))
|
|
{
|
|
adap->restart_needed = FALSE;
|
|
adap->bus_reset_needed = FALSE;
|
|
|
|
if (!mpt_stop(adap, TRUE))
|
|
return 0;
|
|
}
|
|
|
|
adap->config_active = FALSE;
|
|
adap->command_active = FALSE;
|
|
|
|
if (!mpt_start(adap))
|
|
return 0;
|
|
|
|
if (adap->port_type == MPI_PORTFACTS_PORTTYPE_SCSI)
|
|
{
|
|
mpt_init_device_capabilities(adap);
|
|
|
|
for (targ = 0; targ < adap->max_targets; targ++)
|
|
{
|
|
mpt_set_device_capabilities(adap, targ);
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* mpt_stop - stop the IOC (reset it).
|
|
*/
|
|
int
|
|
mpt_stop(mpt_adap_t *adap, int wait)
|
|
{
|
|
time_t limit = time(NULL) + mpt_adjust_delay(adap, 30);
|
|
|
|
// printf("mpt_stop called\n");
|
|
|
|
#if EFI
|
|
EFI_STATUS status;
|
|
|
|
if (adap->disconnected == FALSE)
|
|
{
|
|
EFI_PCI_IO_PROTOCOL *pci_io;
|
|
|
|
if (wait == FALSE)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
if (adap->loaddevice == TRUE)
|
|
{
|
|
printf("This chip controls the device that this utility was loaded from.\n");
|
|
printf("After this command, the load device cannot be accessed again\n");
|
|
printf("to open files, until this utility has been exited and restarted.\n\n");
|
|
}
|
|
|
|
if (!EFI_ERROR(BS->DisconnectController(adap->handle, NULL, NULL)))
|
|
{
|
|
adap->disconnected = TRUE;
|
|
pci_io = adap->pci_io;
|
|
status = pci_io->Attributes(pci_io, EfiPciIoAttributeOperationEnable,
|
|
EFI_PCI_IO_ATTRIBUTE_IO |
|
|
EFI_PCI_IO_ATTRIBUTE_MEMORY |
|
|
EFI_PCI_IO_ATTRIBUTE_BUS_MASTER |
|
|
EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE, NULL);
|
|
|
|
if (status == EFI_UNSUPPORTED)
|
|
{
|
|
pci_io->Attributes(pci_io, EfiPciIoAttributeOperationEnable,
|
|
EFI_PCI_IO_ATTRIBUTE_IO |
|
|
EFI_PCI_IO_ATTRIBUTE_MEMORY |
|
|
EFI_PCI_IO_ATTRIBUTE_BUS_MASTER, NULL);
|
|
}
|
|
}
|
|
|
|
if (adap->partner_adap)
|
|
{
|
|
if (!EFI_ERROR(BS->DisconnectController(adap->partner_adap->handle, NULL, NULL)))
|
|
{
|
|
adap->partner_adap->disconnected = TRUE;
|
|
pci_io = adap->partner_adap->pci_io;
|
|
status = pci_io->Attributes(pci_io, EfiPciIoAttributeOperationEnable,
|
|
EFI_PCI_IO_ATTRIBUTE_IO |
|
|
EFI_PCI_IO_ATTRIBUTE_MEMORY |
|
|
EFI_PCI_IO_ATTRIBUTE_BUS_MASTER |
|
|
EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE, NULL);
|
|
|
|
if (status == EFI_UNSUPPORTED)
|
|
{
|
|
pci_io->Attributes(pci_io, EfiPciIoAttributeOperationEnable,
|
|
EFI_PCI_IO_ATTRIBUTE_IO |
|
|
EFI_PCI_IO_ATTRIBUTE_MEMORY |
|
|
EFI_PCI_IO_ATTRIBUTE_BUS_MASTER, NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
adap->port_online = FALSE;
|
|
|
|
adap->interrupt_mask = MPI_HIM_RIM | MPI_HIM_DIM;
|
|
wl(HOST_INTERRUPT_MASK, rl(HOST_INTERRUPT_MASK) | adap->interrupt_mask);
|
|
|
|
/*
|
|
* Reset the chip.
|
|
*/
|
|
if (adap->device_id == MPI_MANUFACTPAGE_DEVICEID_FC909)
|
|
{
|
|
rl(FC909_BUG); /* work around FC909 bug */
|
|
}
|
|
|
|
if (!(rl(DIAGNOSTIC) & MPI_DIAG_DRWE))
|
|
{
|
|
wl(WRITE_SEQUENCE, 0);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_KEY_VALUE_MASK);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_1ST_KEY_VALUE);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_2ND_KEY_VALUE);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_3RD_KEY_VALUE);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_4TH_KEY_VALUE);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_5TH_KEY_VALUE);
|
|
DELAY(100);
|
|
}
|
|
|
|
if (!(rl(DIAGNOSTIC) & MPI_DIAG_RESET_HISTORY) ||
|
|
((rl(DOORBELL) & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_RESET &&
|
|
(rl(DOORBELL) & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_READY))
|
|
{
|
|
if (adap->device_id == MPI_MANUFACTPAGE_DEVID_SAS1078)
|
|
{
|
|
wl(SAS1078_RESET, 0x7);
|
|
}
|
|
else
|
|
{
|
|
wl(DIAGNOSTIC, MPI_DIAG_RESET_ADAPTER);
|
|
}
|
|
DELAY(50000);
|
|
wl(WRITE_SEQUENCE, 0);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_KEY_VALUE_MASK);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_1ST_KEY_VALUE);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_2ND_KEY_VALUE);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_3RD_KEY_VALUE);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_4TH_KEY_VALUE);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_5TH_KEY_VALUE);
|
|
DELAY(100);
|
|
}
|
|
|
|
wl(DIAGNOSTIC, 0);
|
|
|
|
if (wait == FALSE)
|
|
{
|
|
while (time(NULL) < limit)
|
|
{
|
|
if (rl(DOORBELL) & MPI_IOC_STATE_MASK)
|
|
break;
|
|
if (rl(DIAGNOSTIC) & MPI_DIAG_DISABLE_ARM)
|
|
break;
|
|
DELAY(100);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
if (rl(DIAGNOSTIC) & MPI_DIAG_RESET_ADAPTER)
|
|
{
|
|
printf("\n%s: Failed to clear RESET ADAPTER\n", adap->name);
|
|
if (wFlag)
|
|
fprintf(logFile, "%s: Failed to clear RESET ADAPTER\n",
|
|
adap->name);
|
|
adap->restart_needed = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
adap->bootloader = FALSE;
|
|
|
|
if (mpt_wait_for_ready(adap))
|
|
return 1;
|
|
|
|
if (mpt_fwdownloadboot(adap))
|
|
return 1;
|
|
|
|
if ((rl(DOORBELL) & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_RESET)
|
|
{
|
|
adap->restart_needed = FALSE;
|
|
|
|
printf("\n%s: Failed to leave the RESET state\n", adap->name);
|
|
if (wFlag)
|
|
fprintf(logFile, "%s: Failed to leave the RESET state\n",
|
|
adap->name);
|
|
}
|
|
else
|
|
{
|
|
adap->restart_needed = TRUE;
|
|
|
|
printf("\n%s: Failed to reset properly\n", adap->name);
|
|
if (wFlag)
|
|
fprintf(logFile, "%s: Failed to reset properly\n",
|
|
adap->name);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* mpt_start - start the IOC (completely initialize it).
|
|
*/
|
|
int
|
|
mpt_start(mpt_adap_t *adap)
|
|
{
|
|
int port;
|
|
|
|
// printf("mpt_start called\n");
|
|
|
|
if (adap->bootloader == TRUE)
|
|
{
|
|
printf("\nBootLoader firmware cannot be made fully operational!\n");
|
|
return 0;
|
|
}
|
|
|
|
if (!mpt_issue_ioc_facts(adap))
|
|
{
|
|
printf("%s: Failed to send IOCFacts\n", adap->name);
|
|
return 0;
|
|
}
|
|
|
|
if (!mpt_issue_ioc_init(adap))
|
|
{
|
|
printf("%s: Failed to send IOCInit\n", adap->name);
|
|
return 0;
|
|
}
|
|
|
|
if (!mpt_initialize(adap))
|
|
{
|
|
printf("%s: Failed to finish initialization of IOC\n", adap->name);
|
|
return 0;
|
|
}
|
|
|
|
for (port = 0; port < adap->port_count; port++)
|
|
{
|
|
if (!mpt_issue_port_facts(adap, port))
|
|
{
|
|
printf("%s: Failed to send PortFacts to port %d\n", adap->name, port);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (adap->port_enable_needed)
|
|
{
|
|
adap->port_online = mpt_port_online(adap);
|
|
}
|
|
|
|
#if 0 // skip this for DOS and EFI, as it doesn't really help
|
|
if (!mpt_issue_event_notification(adap))
|
|
{
|
|
printf("%s: failed to send EventNotification\n", adap->name);
|
|
}
|
|
#endif
|
|
|
|
if (adap->port_type == MPI_PORTFACTS_PORTTYPE_SCSI)
|
|
{
|
|
if (!mpt_set_on_bus_timer(adap, 1000))
|
|
{
|
|
printf("%s: Failed to set SCSI On Bus Timer\n", adap->name);
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* mpt_port_online - bring the port online.
|
|
*/
|
|
int
|
|
mpt_port_online(mpt_adap_t *adap)
|
|
{
|
|
int port;
|
|
|
|
// printf("mpt_port_online called\n");
|
|
|
|
for (port = 0; port < adap->port_count; port++)
|
|
{
|
|
if (adap->port_type == MPI_PORTFACTS_PORTTYPE_SAS)
|
|
{
|
|
//TODO: MPI12.5 - This is where it crashes
|
|
if (doSasChangeWwid(adap->port, 1) == 1)
|
|
{
|
|
printf("\nThe SAS WWID is zero -- the port will not be enabled\n");
|
|
printf("\nUse menu option 18 then option 99 to fix this problem\n");
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (!mpt_issue_port_enable(adap, port))
|
|
{
|
|
printf("%s: Failed to send PortEnable to port %d\n", adap->name, port);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int
|
|
mpt_wait_for_doorbell(mpt_adap_t *adap, time_t limit)
|
|
{
|
|
U32 doorbell;
|
|
int state;
|
|
|
|
while (time(NULL) < limit)
|
|
{
|
|
if (adap->restart_needed == TRUE)
|
|
{
|
|
return 0;
|
|
}
|
|
doorbell = rl(DOORBELL);
|
|
state = doorbell & MPI_IOC_STATE_MASK;
|
|
if (state == MPI_IOC_STATE_FAULT)
|
|
{
|
|
printf("\n%s: MPT Firmware Fault, code %04x\n",
|
|
adap->name, doorbell & MPI_DOORBELL_DATA_MASK);
|
|
if (wFlag)
|
|
fprintf(logFile, "%s: MPT Firmware Fault, code %04x\n",
|
|
adap->name, doorbell & MPI_DOORBELL_DATA_MASK);
|
|
|
|
printf("\nDo you want to continue? [Yes or No, default is No] ");
|
|
|
|
if (getYesNoAnswer(0) != 1)
|
|
break;
|
|
|
|
printf("\n");
|
|
|
|
adap->restart_needed = TRUE;
|
|
return 0;
|
|
}
|
|
if (rl(HOST_INTERRUPT_STATUS) & MPI_HIS_DOORBELL_INTERRUPT)
|
|
{
|
|
return 1;
|
|
}
|
|
DELAY(1);
|
|
}
|
|
|
|
printf("%s: Failed in mpt_wait_for_doorbell, Doorbell = %08x\n",
|
|
adap->name, doorbell);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
mpt_wait_for_response(mpt_adap_t *adap, time_t limit)
|
|
{
|
|
U32 doorbell;
|
|
int state;
|
|
|
|
while (time(NULL) < limit)
|
|
{
|
|
if (adap->restart_needed == TRUE)
|
|
{
|
|
return 0;
|
|
}
|
|
doorbell = rl(DOORBELL);
|
|
state = doorbell & MPI_IOC_STATE_MASK;
|
|
if (state == MPI_IOC_STATE_FAULT)
|
|
{
|
|
printf("\n%s: MPT Firmware Fault, code %04x\n",
|
|
adap->name, doorbell & MPI_DOORBELL_DATA_MASK);
|
|
if (wFlag)
|
|
fprintf(logFile, "%s: MPT Firmware Fault, code %04x\n",
|
|
adap->name, doorbell & MPI_DOORBELL_DATA_MASK);
|
|
|
|
printf("\nHit Enter to continue ");
|
|
|
|
getYesNoAnswer(0);
|
|
|
|
printf("\n");
|
|
|
|
adap->restart_needed = TRUE;
|
|
return 0;
|
|
}
|
|
if (!(rl(HOST_INTERRUPT_STATUS) & MPI_HIS_IOP_DOORBELL_STATUS))
|
|
{
|
|
return 1;
|
|
}
|
|
DELAY(1);
|
|
}
|
|
|
|
printf("%s: Failed in mpt_wait_for_response, Doorbell = %08x\n",
|
|
adap->name, doorbell);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
mpt_send_message(mpt_adap_t *adap, int length, time_t limit)
|
|
{
|
|
U32 doorbell;
|
|
U32 *message = adap->shared->message;
|
|
int state;
|
|
int i;
|
|
|
|
doorbell = rl(DOORBELL);
|
|
state = doorbell & MPI_IOC_STATE_MASK;
|
|
if (state == MPI_IOC_STATE_FAULT)
|
|
{
|
|
printf("\n%s: MPT Firmware Fault, code %04x\n",
|
|
adap->name, doorbell & MPI_DOORBELL_DATA_MASK);
|
|
if (wFlag)
|
|
fprintf(logFile, "%s: MPT Firmware Fault, code %04x\n",
|
|
adap->name, doorbell & MPI_DOORBELL_DATA_MASK);
|
|
|
|
printf("\nHit Enter to continue ");
|
|
|
|
getYesNoAnswer(0);
|
|
|
|
printf("\n");
|
|
|
|
adap->restart_needed = TRUE;
|
|
return 0;
|
|
}
|
|
if (state == MPI_IOC_STATE_RESET)
|
|
{
|
|
adap->restart_needed = TRUE;
|
|
return 0;
|
|
}
|
|
if (doorbell & MPI_DOORBELL_USED)
|
|
{
|
|
printf("%s: Doorbell already active\n", adap->name);
|
|
adap->restart_needed = TRUE;
|
|
return 0;
|
|
}
|
|
wl(HOST_INTERRUPT_STATUS, 0);
|
|
wl(DOORBELL, (MPI_FUNCTION_HANDSHAKE << MPI_DOORBELL_FUNCTION_SHIFT) |
|
|
((length / 4) << MPI_DOORBELL_ADD_DWORDS_SHIFT));
|
|
if (!mpt_wait_for_doorbell(adap, limit))
|
|
return 0;
|
|
wl(HOST_INTERRUPT_STATUS, 0);
|
|
if (!mpt_wait_for_response(adap, limit))
|
|
return 0;
|
|
for (i = 0; i < length / 4; i++)
|
|
{
|
|
wl(DOORBELL, get32x(message[i]));
|
|
if (!mpt_wait_for_response(adap, limit))
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int
|
|
mpt_receive_data(mpt_adap_t *adap, int length, time_t limit)
|
|
{
|
|
int i;
|
|
int real_length;
|
|
U16 value;
|
|
U16 *data = adap->shared->data;
|
|
MPIDefaultReply_t *reply = (MPIDefaultReply_t *)data;
|
|
U16 status;
|
|
|
|
bzero(data, length);
|
|
real_length = 4; /* enough for the header to start, fix up later */
|
|
for (i = 0; i < real_length / 2; i++)
|
|
{
|
|
if (!mpt_wait_for_doorbell(adap, limit))
|
|
return 0;
|
|
value = (U16)rl(DOORBELL);
|
|
if (i == 1)
|
|
real_length = (value & ~0xff00) * 4;
|
|
if (i < length / 2)
|
|
data[i] = get16x(value);
|
|
wl(HOST_INTERRUPT_STATUS, 0);
|
|
}
|
|
if (!mpt_wait_for_doorbell(adap, limit))
|
|
return 0;
|
|
wl(HOST_INTERRUPT_STATUS, 0);
|
|
|
|
status = get16(reply->IOCStatus) & MPI_IOCSTATUS_MASK;
|
|
if (status == MPI_IOCSTATUS_SUCCESS ||
|
|
status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE ||
|
|
status == MPI_IOCSTATUS_CONFIG_INVALID_DATA ||
|
|
status == MPI_IOCSTATUS_CONFIG_INVALID_ACTION)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
mpt_issue_command_and_wait(mpt_adap_t *adap, int wait)
|
|
{
|
|
U8 function = ((MPIHeader_t *)adap->shared->message)->Function;
|
|
int handle;
|
|
time_t limit = time(NULL) + wait;
|
|
|
|
adap->command_active = TRUE;
|
|
|
|
if (mpi1)
|
|
{
|
|
if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
|
|
{
|
|
if (mpt_send_message(adap, sizeof(SCSITaskMgmt_t), limit) != 1)
|
|
{
|
|
printf("mpt_send_message failed!\n");
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wl(REQUEST_QUEUE, (U32)adap->shared_ba + (U32)offsetof(mpt_shared_t, message));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
|
|
{
|
|
/* SCSI Task Mgmt requests have to use high priority */
|
|
wl2(REQUEST_DESCRIPTOR_POST_LOW, (1 << 16) + MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY);
|
|
wl2(REQUEST_DESCRIPTOR_POST_HIGH, 0);
|
|
}
|
|
else if (function == MPI_FUNCTION_SCSI_IO_REQUEST)
|
|
{
|
|
handle = get16(((Mpi2SCSIIORequest_t *)adap->shared->message)->DevHandle);
|
|
|
|
/* SCSI requests have to use SCSI IO and supply a handle */
|
|
wl2(REQUEST_DESCRIPTOR_POST_LOW, (1 << 16) + MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO);
|
|
wl2(REQUEST_DESCRIPTOR_POST_HIGH, handle << 16);
|
|
}
|
|
else if (function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
|
|
{
|
|
handle = get16(((Mpi2SCSIIORequest_t *)adap->shared->message)->DevHandle);
|
|
|
|
/* RAID Passthru requests have to use default descriptor and supply a handle */
|
|
wl2(REQUEST_DESCRIPTOR_POST_LOW, (1 << 16) + MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE);
|
|
wl2(REQUEST_DESCRIPTOR_POST_HIGH, handle << 16);
|
|
}
|
|
else
|
|
{
|
|
wl2(REQUEST_DESCRIPTOR_POST_LOW, (1 << 16) + MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE);
|
|
wl2(REQUEST_DESCRIPTOR_POST_HIGH, 0);
|
|
}
|
|
}
|
|
|
|
while (time(NULL) < limit)
|
|
{
|
|
if (mpt_watchdog(adap))
|
|
{
|
|
break;
|
|
}
|
|
mpt_interrupt(adap);
|
|
if (adap->command_active == TRUE)
|
|
{
|
|
DELAY(1);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (adap->command_active == TRUE)
|
|
{
|
|
if (time(NULL) >= limit)
|
|
printf("timeout occurred!\n");
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int
|
|
mpt_issue_config_and_wait(mpt_adap_t *adap, int wait)
|
|
{
|
|
time_t limit = time(NULL) + wait;
|
|
|
|
adap->config_active = TRUE;
|
|
|
|
if (mpi1)
|
|
{
|
|
wl(REQUEST_QUEUE, (U32)adap->shared_ba + (U32)offsetof(mpt_shared_t, message));
|
|
}
|
|
else
|
|
{
|
|
wl2(REQUEST_DESCRIPTOR_POST_LOW, (1 << 16) + MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE);
|
|
wl2(REQUEST_DESCRIPTOR_POST_HIGH, 0);
|
|
}
|
|
|
|
while (time(NULL) < limit)
|
|
{
|
|
if (adap->restart_needed == TRUE)
|
|
{
|
|
return 0;
|
|
}
|
|
mpt_interrupt(adap);
|
|
if (adap->config_active == TRUE)
|
|
{
|
|
DELAY(1);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (adap->config_active == TRUE)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* mpt_issue_ioc_facts - issue an IOCFacts command to the IOC.
|
|
*/
|
|
int
|
|
mpt_issue_ioc_facts(mpt_adap_t *adap)
|
|
{
|
|
IOCFacts_t *request = (IOCFacts_t *)adap->shared->message;
|
|
IOCFactsReply_t *reply = (IOCFactsReply_t *)adap->shared->data;
|
|
time_t limit = time(NULL) + 10;
|
|
int t;
|
|
|
|
// printf("%s: sending IOCFacts\n", adap->name);
|
|
|
|
bzero(request, sizeof(*request));
|
|
|
|
request->Function = MPI_FUNCTION_IOC_FACTS;
|
|
|
|
logMptCommandReq(adap->port, request, sizeof(*request));
|
|
|
|
if (!mpt_send_message(adap, sizeof(*request), limit))
|
|
{
|
|
printf("%s: mpt_send_message / IOCFacts failed\n", adap->name);
|
|
return 0;
|
|
}
|
|
|
|
t = mpt_receive_data(adap, sizeof(*reply), limit);
|
|
|
|
logMptCommandRep(adap->port, request, sizeof(*request), reply, sizeof(*reply), t);
|
|
|
|
if (!t)
|
|
{
|
|
printf("%s: mpt_receive_data / IOCFacts failed\n", adap->name);
|
|
return 0;
|
|
}
|
|
|
|
adap->mpt_version = get16(reply->MsgVersion);
|
|
|
|
if (mpi2)
|
|
{
|
|
return mpt2_issue_ioc_facts(adap);
|
|
}
|
|
|
|
if (reply->WhoInit == MPI_WHOINIT_PCI_PEER)
|
|
{
|
|
printf("%s: WhoInit is PCI Peer!\n", adap->name);
|
|
return 0;
|
|
}
|
|
|
|
// printf("BlockSize = %x\n", reply->BlockSize);
|
|
// printf("ReplyQueueDepth = %x\n", get16(reply->ReplyQueueDepth));
|
|
// printf("RequestFrameSize = %x\n", get16(reply->RequestFrameSize));
|
|
// printf("GlobalCredits = %x\n", get16(reply->GlobalCredits));
|
|
// printf("NumberOfPorts = %x\n", reply->NumberOfPorts);
|
|
|
|
// if (get16(reply->MsgVersion) < MPI_VERSION_01_02)
|
|
// printf("%s: MPT Version = %04x, Firmware Version = %04x\n",
|
|
// adap->name, get16(reply->MsgVersion),
|
|
// get16(reply->Reserved_0101_FWVersion));
|
|
// else
|
|
// printf("%s: MPT Version = %04x, Firmware Version = %08x\n",
|
|
// adap->name, get16(reply->MsgVersion),
|
|
// get32(reply->FWVersion.Word));
|
|
|
|
adap->message_size = get16(reply->RequestFrameSize) * 4;
|
|
adap->reply_depth = get16(reply->ReplyQueueDepth);
|
|
adap->credits = get16(reply->GlobalCredits);
|
|
adap->port_count = reply->NumberOfPorts;
|
|
adap->block_size = reply->BlockSize;
|
|
|
|
adap->hrsm_capable = FALSE;
|
|
if (get16(reply->MsgVersion) >= MPI_VERSION_01_05)
|
|
if (get32(reply->IOCCapabilities) & MPI_IOCFACTS_CAPABILITY_REPLY_HOST_SIGNAL)
|
|
adap->hrsm_capable = TRUE;
|
|
if (adap->device_id == MPI_MANUFACTPAGE_DEVID_SAS1064 ||
|
|
adap->device_id == MPI_MANUFACTPAGE_DEVID_SAS1064E ||
|
|
adap->device_id == MPI_MANUFACTPAGE_DEVID_SAS1066 ||
|
|
adap->device_id == MPI_MANUFACTPAGE_DEVID_SAS1066E ||
|
|
adap->device_id == MPI_MANUFACTPAGE_DEVID_SAS1068 ||
|
|
adap->device_id == MPI_MANUFACTPAGE_DEVID_SAS1068E)
|
|
{
|
|
U32 version = get32(reply->FWVersion.Word);
|
|
|
|
if (version < 0x00040100)
|
|
adap->hrsm_capable = FALSE;
|
|
if (version >= 0x01000000 && version < 0x01050000)
|
|
adap->hrsm_capable = FALSE;
|
|
}
|
|
|
|
if (reply->MaxDevices)
|
|
if (adap->max_targets > reply->MaxDevices)
|
|
adap->max_targets = reply->MaxDevices;
|
|
|
|
if (adap->port_type == MPI_PORTFACTS_PORTTYPE_SCSI)
|
|
if (adap->max_targets > 16)
|
|
adap->max_targets = 16;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int
|
|
mpt2_issue_ioc_facts(mpt_adap_t *adap)
|
|
{
|
|
Mpi2IOCFactsRequest_t *request = (Mpi2IOCFactsRequest_t *)adap->shared->message;
|
|
Mpi2IOCFactsReply_t *reply = (Mpi2IOCFactsReply_t *)adap->shared->data;
|
|
time_t limit = time(NULL) + 10;
|
|
int t;
|
|
|
|
bzero(request, sizeof(*request));
|
|
|
|
request->Function = MPI2_FUNCTION_IOC_FACTS;
|
|
|
|
logMptCommandReq(adap->port, request, sizeof(*request));
|
|
|
|
if (!mpt_send_message(adap, sizeof(*request), limit))
|
|
{
|
|
printf("%s: mpt_send_message / IOCFacts failed\n", adap->name);
|
|
return 0;
|
|
}
|
|
|
|
t = mpt_receive_data(adap, sizeof(*reply), limit);
|
|
|
|
logMptCommandRep(adap->port, request, sizeof(*request), reply, sizeof(*reply), t);
|
|
|
|
if (!t)
|
|
{
|
|
printf("%s: mpt_receive_data / IOCFacts failed\n", adap->name);
|
|
return 0;
|
|
}
|
|
|
|
if (reply->WhoInit == MPI2_WHOINIT_PCI_PEER)
|
|
{
|
|
printf("%s: WhoInit is PCI Peer!\n", adap->name);
|
|
return 0;
|
|
}
|
|
|
|
// printf("MaxReplyDescriptorPostQueueDepth = %x\n", get16(reply->MaxReplyDescriptorPostQueueDepth));
|
|
// printf("IOCRequestFrameSize = %x\n", get16(reply->IOCRequestFrameSize));
|
|
// printf("RequestCredit = %x\n", get16(reply->RequestCredit));
|
|
// printf("NumberOfPorts = %x\n", reply->NumberOfPorts);
|
|
|
|
// printf("%s: MPT Version = %04x, Firmware Version = %08x\n",
|
|
// adap->name, get16(reply->MsgVersion),
|
|
// get32(reply->FWVersion.Word));
|
|
|
|
adap->message_size = get16(reply->IOCRequestFrameSize) * 4;
|
|
adap->reply_depth = get16(reply->MaxReplyDescriptorPostQueueDepth);
|
|
adap->credits = get16(reply->RequestCredit);
|
|
adap->port_count = reply->NumberOfPorts;
|
|
|
|
adap->hrsm_capable = FALSE;
|
|
|
|
if (get16(reply->MaxTargets))
|
|
if (adap->max_targets > get16(reply->MaxTargets))
|
|
adap->max_targets = get16(reply->MaxTargets);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* mpt_issue_ioc_init - issue an IOCInit command to the IOC.
|
|
*/
|
|
int
|
|
mpt_issue_ioc_init(mpt_adap_t *adap)
|
|
{
|
|
IOCInit_t *request = (IOCInit_t *)adap->shared->message;
|
|
IOCInitReply_t *reply = (IOCInitReply_t *)adap->shared->data;
|
|
time_t limit = time(NULL) + 30;
|
|
int t;
|
|
#if EFI
|
|
_U32 high = set32((U32)(adap->shared_ba >> 32));
|
|
#endif
|
|
|
|
// printf("%s: sending IOCInit\n", adap->name);
|
|
|
|
if (mpi2)
|
|
{
|
|
return mpt2_issue_ioc_init(adap);
|
|
}
|
|
|
|
bzero(request, sizeof(*request));
|
|
|
|
request->Function = MPI_FUNCTION_IOC_INIT;
|
|
request->WhoInit = MPI_WHOINIT_HOST_DRIVER;
|
|
request->MaxDevices = adap->max_targets;
|
|
request->MaxBuses = 1;
|
|
request->MsgContext = set32(COMMAND_CONTEXT);
|
|
request->ReplyFrameSize = set16(sizeof(adap->shared->replies[0]));
|
|
#if EFI
|
|
request->HostMfaHighAddr = high;
|
|
request->SenseBufferHighAddr = high;
|
|
#endif
|
|
request->MsgVersion = set16(MPI_VERSION);
|
|
request->HeaderVersion = set16(MPI_HEADER_VERSION);
|
|
|
|
if (adap->hrsm_capable == TRUE)
|
|
{
|
|
adap->hrsm_value = 0;
|
|
request->Flags |= MPI_IOCINIT_FLAGS_REPLY_FIFO_HOST_SIGNAL;
|
|
request->ReplyFifoHostSignalingAddr =
|
|
set32((U32)adap->shared_ba +
|
|
(U32)offsetof(mpt_shared_t, hrsm_value));
|
|
}
|
|
|
|
logMptCommandReq(adap->port, request, sizeof(*request));
|
|
|
|
if (!mpt_send_message(adap, sizeof(*request), limit))
|
|
{
|
|
printf("%s: mpt_send_message / IOCInit failed\n", adap->name);
|
|
return 0;
|
|
}
|
|
|
|
t = mpt_receive_data(adap, sizeof(*reply), limit);
|
|
|
|
logMptCommandRep(adap->port, request, sizeof(*request), reply, sizeof(*reply), t);
|
|
|
|
if (!t)
|
|
{
|
|
printf("%s: mpt_receive_data / IOCInit failed\n", adap->name);
|
|
return 0;
|
|
}
|
|
reply = reply;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int
|
|
mpt2_issue_ioc_init(mpt_adap_t *adap)
|
|
{
|
|
Mpi2IOCInitRequest_t *request = (Mpi2IOCInitRequest_t *)adap->shared->message;
|
|
Mpi2IOCInitReply_t *reply = (Mpi2IOCInitReply_t *)adap->shared->data;
|
|
time_t limit = time(NULL) + 30;
|
|
int t;
|
|
time_t now;
|
|
uint64_t nowMsec;
|
|
#if EFI
|
|
_U32 high = set32((U32)(adap->shared_ba >> 32));
|
|
#endif
|
|
|
|
bzero(request, sizeof(*request));
|
|
|
|
request->Function = MPI2_FUNCTION_IOC_INIT;
|
|
request->WhoInit = MPI2_WHOINIT_SYSTEM_BIOS;
|
|
request->SystemRequestFrameSize = set16(sizeof(adap->shared->message) / 4);
|
|
request->ReplyDescriptorPostQueueDepth = set16(REPLY_POST_SIZE);
|
|
request->ReplyFreeQueueDepth = set16(REPLY_FREE_SIZE);
|
|
request->SystemRequestFrameBaseAddress.Low =
|
|
set32((U32)adap->shared_ba + offsetof(mpt_shared_t, message) - sizeof(adap->shared->message));
|
|
request->ReplyDescriptorPostQueueAddress.Low =
|
|
set32((U32)adap->shared_ba + offsetof(mpt_shared_t, post_queue));
|
|
request->ReplyFreeQueueAddress.Low =
|
|
set32((U32)adap->shared_ba + offsetof(mpt_shared_t, free_queue));
|
|
#if EFI
|
|
request->SystemReplyAddressHigh = high;
|
|
request->SenseBufferAddressHigh = high;
|
|
request->SystemRequestFrameBaseAddress.High = high;
|
|
request->ReplyDescriptorPostQueueAddress.High = high;
|
|
request->ReplyFreeQueueAddress.High = high;
|
|
#endif
|
|
request->MsgVersion = set16(MPI2_VERSION);
|
|
request->HeaderVersion = set16(MPI2_HEADER_VERSION);
|
|
|
|
time(&now);
|
|
nowMsec = ((uint64_t)(now)) * 1000;
|
|
request->TimeStamp.Low = set32((U32)(nowMsec & 0x00000000FFFFFFFF));
|
|
request->TimeStamp.High = set32((U32)((nowMsec & 0xFFFFFFFF00000000) >> 32));
|
|
|
|
adap->free_index = 0;
|
|
adap->post_index = 0;
|
|
|
|
logMptCommandReq(adap->port, request, sizeof(*request));
|
|
|
|
if (!mpt_send_message(adap, sizeof(*request), limit))
|
|
{
|
|
printf("%s: mpt_send_message / IOCInit failed\n", adap->name);
|
|
return 0;
|
|
}
|
|
|
|
t = mpt_receive_data(adap, sizeof(*reply), limit);
|
|
|
|
logMptCommandRep(adap->port, request, sizeof(*request), reply, sizeof(*reply), t);
|
|
|
|
if (!t)
|
|
{
|
|
printf("%s: mpt_receive_data / IOCInit failed\n", adap->name);
|
|
return 0;
|
|
}
|
|
reply = reply;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* mpt_initialize - finish initialization of IOC.
|
|
*/
|
|
int
|
|
mpt_initialize(mpt_adap_t *adap)
|
|
{
|
|
U32 doorbell;
|
|
int i;
|
|
int state;
|
|
time_t limit = time(NULL) + 10;
|
|
|
|
// printf("%s: initializing IOC\n", adap->name);
|
|
|
|
while (time(NULL) < limit)
|
|
{
|
|
doorbell = rl(DOORBELL);
|
|
state = doorbell & MPI_IOC_STATE_MASK;
|
|
if (state == MPI_IOC_STATE_OPERATIONAL)
|
|
break;
|
|
DELAY(1);
|
|
}
|
|
|
|
if (state != MPI_IOC_STATE_OPERATIONAL)
|
|
{
|
|
if (state == MPI_IOC_STATE_FAULT)
|
|
{
|
|
printf("\n%s: MPT Firmware Fault, code %04x\n",
|
|
adap->name, doorbell & MPI_DOORBELL_DATA_MASK);
|
|
if (wFlag)
|
|
fprintf(logFile, "%s: MPT Firmware Fault, code %04x\n",
|
|
adap->name, doorbell & MPI_DOORBELL_DATA_MASK);
|
|
|
|
printf("\nHit Enter to continue ");
|
|
|
|
getYesNoAnswer(0);
|
|
|
|
printf("\n");
|
|
}
|
|
adap->restart_needed = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
if (mpi1)
|
|
{
|
|
for (i = 0; i < NUM_REPLIES; i++)
|
|
{
|
|
wl(REPLY_QUEUE, (U32)adap->shared_ba + (U32)offsetof(mpt_shared_t, replies[i]));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < NUM_REPLIES; i++)
|
|
{
|
|
adap->shared->free_queue[i] =
|
|
(U32)adap->shared_ba + (U32)offsetof(mpt_shared_t, replies[i]);
|
|
}
|
|
adap->free_index = i;
|
|
wl2(REPLY_FREE_HOST_INDEX, i);
|
|
bzero(adap->shared->post_queue, sizeof(adap->shared->post_queue));
|
|
for (i = 0; i < REPLY_POST_SIZE; i++)
|
|
{
|
|
adap->shared->post_queue[i].ReplyFlags = MPI2_RPY_DESCRIPT_FLAGS_UNUSED;
|
|
}
|
|
}
|
|
|
|
adap->interrupt_mask &= ~MPI_HIM_RIM;
|
|
// wl(HOST_INTERRUPT_MASK, adap->interrupt_mask);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* mpt_issue_port_facts - issue a PortFacts command to the IOC.
|
|
*/
|
|
int
|
|
mpt_issue_port_facts(mpt_adap_t *adap, int port)
|
|
{
|
|
PortFacts_t *request = (PortFacts_t *)adap->shared->message;
|
|
PortFactsReply_t *reply = (PortFactsReply_t *)adap->shared->data;
|
|
time_t limit = time(NULL) + 10;
|
|
int t;
|
|
|
|
// printf("%s: sending PortFacts to port %d\n", adap->name, port);
|
|
|
|
if (mpi2)
|
|
{
|
|
return mpt2_issue_port_facts(adap, port);
|
|
}
|
|
|
|
bzero(request, sizeof(*request));
|
|
|
|
request->Function = MPI_FUNCTION_PORT_FACTS;
|
|
request->PortNumber = port;
|
|
request->MsgContext = set32(COMMAND_CONTEXT);
|
|
|
|
logMptCommandReq(adap->port, request, sizeof(*request));
|
|
|
|
if (!mpt_send_message(adap, sizeof(*request), limit))
|
|
{
|
|
printf("%s: mpt_send_message / PortFacts failed\n", adap->name);
|
|
return 0;
|
|
}
|
|
|
|
t = mpt_receive_data(adap, sizeof(*reply), limit);
|
|
|
|
logMptCommandRep(adap->port, request, sizeof(*request), reply, sizeof(*reply), t);
|
|
|
|
if (!t)
|
|
{
|
|
printf("%s: mpt_receive_data / PortFacts failed\n", adap->name);
|
|
return 0;
|
|
}
|
|
|
|
adap->port_type = reply->PortType;
|
|
adap->host_id = get16(reply->PortSCSIID);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int
|
|
mpt2_issue_port_facts(mpt_adap_t *adap, int port)
|
|
{
|
|
Mpi2PortFactsRequest_t *request = (Mpi2PortFactsRequest_t *)adap->shared->message;
|
|
Mpi2PortFactsReply_t *reply = (Mpi2PortFactsReply_t *)adap->shared->data;
|
|
time_t limit = time(NULL) + 10;
|
|
int t;
|
|
|
|
bzero(request, sizeof(*request));
|
|
|
|
request->Function = MPI2_FUNCTION_PORT_FACTS;
|
|
request->PortNumber = port;
|
|
|
|
logMptCommandReq(adap->port, request, sizeof(*request));
|
|
|
|
if (!mpt_send_message(adap, sizeof(*request), limit))
|
|
{
|
|
printf("%s: mpt_send_message / PortFacts failed\n", adap->name);
|
|
return 0;
|
|
}
|
|
|
|
t = mpt_receive_data(adap, sizeof(*reply), limit);
|
|
|
|
logMptCommandRep(adap->port, request, sizeof(*request), reply, sizeof(*reply), t);
|
|
|
|
if (!t)
|
|
{
|
|
printf("%s: mpt_receive_data / PortFacts failed\n", adap->name);
|
|
return 0;
|
|
}
|
|
|
|
adap->port_type = reply->PortType;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* mpt_issue_port_enable - issue a PortEnable command to the IOC.
|
|
*/
|
|
int
|
|
mpt_issue_port_enable(mpt_adap_t *adap, int port)
|
|
{
|
|
PortEnable_t *request = (PortEnable_t *)adap->shared->message;
|
|
MPIDefaultReply_t *reply = (MPIDefaultReply_t *)adap->shared->data;
|
|
time_t limit = time(NULL) + 120;
|
|
int t;
|
|
|
|
// printf("%s: sending PortEnable to port %d\n", adap->name, port);
|
|
|
|
if (mpi2)
|
|
{
|
|
return mpt2_issue_port_enable(adap, port);
|
|
}
|
|
|
|
bzero(request, sizeof(*request));
|
|
|
|
request->Function = MPI_FUNCTION_PORT_ENABLE;
|
|
request->PortNumber = port;
|
|
request->MsgContext = set32(COMMAND_CONTEXT);
|
|
|
|
logMptCommandReq(adap->port, request, sizeof(*request));
|
|
|
|
if (!mpt_send_message(adap, sizeof(*request), limit))
|
|
{
|
|
printf("%s: mpt_send_message / PortEnable failed\n", adap->name);
|
|
return 0;
|
|
}
|
|
|
|
t = mpt_receive_data(adap, sizeof(*reply), limit);
|
|
|
|
logMptCommandRep(adap->port, request, sizeof(*request), reply, sizeof(*reply), t);
|
|
|
|
if (!t)
|
|
{
|
|
printf("%s: mpt_receive_data / PortEnable failed\n", adap->name);
|
|
return 0;
|
|
}
|
|
reply = reply;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int
|
|
mpt2_issue_port_enable(mpt_adap_t *adap, int port)
|
|
{
|
|
Mpi2PortEnableRequest_t *request = (Mpi2PortEnableRequest_t *)adap->shared->message;
|
|
Mpi2PortEnableReply_t *reply = (Mpi2PortEnableReply_t *)adap->shared->data;
|
|
time_t limit = time(NULL) + 120;
|
|
int t;
|
|
|
|
bzero(request, sizeof(*request));
|
|
|
|
request->Function = MPI2_FUNCTION_PORT_ENABLE;
|
|
request->VP_ID = port;
|
|
|
|
logMptCommandReq(adap->port, request, sizeof(*request));
|
|
|
|
if (!mpt_send_message(adap, sizeof(*request), limit))
|
|
{
|
|
printf("%s: mpt_send_message / PortEnable failed\n", adap->name);
|
|
return 0;
|
|
}
|
|
|
|
t = mpt_receive_data(adap, sizeof(*reply), limit);
|
|
|
|
logMptCommandRep(adap->port, request, sizeof(*request), reply, sizeof(*reply), t);
|
|
|
|
if (!t)
|
|
{
|
|
printf("%s: mpt_receive_data / PortEnable failed\n", adap->name);
|
|
return 0;
|
|
}
|
|
reply = reply;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* mpt_issue_event_notification - issue an EventNotification command to the IOC.
|
|
*/
|
|
int
|
|
mpt_issue_event_notification(mpt_adap_t *adap)
|
|
{
|
|
EventNotification_t *request = (EventNotification_t *)adap->shared->message;
|
|
EventNotificationReply_t *reply = (EventNotificationReply_t *)adap->shared->data;
|
|
time_t limit = time(NULL) + 10;
|
|
int t;
|
|
|
|
// printf("%s: sending EventNotification\n", adap->name);
|
|
|
|
if (mpi2)
|
|
{
|
|
return mpt2_issue_event_notification(adap);
|
|
}
|
|
|
|
bzero(request, sizeof(*request));
|
|
|
|
request->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
|
|
request->Switch = MPI_EVENT_NOTIFICATION_SWITCH_ON;
|
|
request->MsgContext = set32(COMMAND_CONTEXT);
|
|
|
|
logMptCommandReq(adap->port, request, sizeof(*request));
|
|
|
|
if (!mpt_send_message(adap, sizeof(*request), limit))
|
|
{
|
|
printf("%s: mpt_send_message / EventNotification failed\n", adap->name);
|
|
return 0;
|
|
}
|
|
|
|
t = mpt_receive_data(adap, sizeof(*reply), limit);
|
|
|
|
logMptCommandRep(adap->port, request, sizeof(*request), reply, sizeof(*reply), t);
|
|
|
|
if (!t)
|
|
{
|
|
printf("%s: mpt_receive_data / EventNotification failed\n", adap->name);
|
|
return 0;
|
|
}
|
|
reply = reply;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int
|
|
mpt2_issue_event_notification(mpt_adap_t *adap)
|
|
{
|
|
Mpi2EventNotificationRequest_t *request = (Mpi2EventNotificationRequest_t *)adap->shared->message;
|
|
Mpi2EventNotificationReply_t *reply = (Mpi2EventNotificationReply_t *)adap->shared->data;
|
|
time_t limit = time(NULL) + 10;
|
|
int t;
|
|
|
|
bzero(request, sizeof(*request));
|
|
|
|
request->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
|
|
|
|
logMptCommandReq(adap->port, request, sizeof(*request));
|
|
|
|
if (!mpt_send_message(adap, sizeof(*request), limit))
|
|
{
|
|
printf("%s: mpt_send_message / EventNotification failed\n", adap->name);
|
|
return 0;
|
|
}
|
|
|
|
t = mpt_receive_data(adap, sizeof(*reply), limit);
|
|
|
|
logMptCommandRep(adap->port, request, sizeof(*request), reply, sizeof(*reply), t);
|
|
|
|
if (!t)
|
|
{
|
|
printf("%s: mpt_receive_data / EventNotification failed\n", adap->name);
|
|
return 0;
|
|
}
|
|
reply = reply;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* mpt_watchdog - routine that acts as a watchdog.
|
|
*/
|
|
int
|
|
mpt_watchdog(mpt_adap_t *adap)
|
|
{
|
|
U32 doorbell;
|
|
int state;
|
|
|
|
if (mpi2) // move code to mpt_interrupt, so we don't poll during DMA
|
|
{
|
|
doorbell = rl(DOORBELL);
|
|
state = doorbell & MPI_IOC_STATE_MASK;
|
|
if (state != MPI_IOC_STATE_OPERATIONAL)
|
|
{
|
|
if (state == MPI_IOC_STATE_FAULT)
|
|
{
|
|
printf("%s: MPT Firmware Fault, code %04x\n",
|
|
adap->name, doorbell & MPI_DOORBELL_DATA_MASK);
|
|
if (wFlag)
|
|
fprintf(logFile, "%s: MPT Firmware Fault, code %04x\n",
|
|
adap->name, doorbell & MPI_DOORBELL_DATA_MASK);
|
|
|
|
printf("\nHit Enter to Continue ");
|
|
|
|
getYesNoAnswer(0);
|
|
|
|
printf("\n");
|
|
}
|
|
adap->restart_needed = TRUE;
|
|
}
|
|
}
|
|
|
|
if (adap->restart_needed == TRUE)
|
|
{
|
|
mpt_restart(adap);
|
|
return 1;
|
|
}
|
|
else if (adap->bus_reset_needed == TRUE)
|
|
{
|
|
adap->bus_reset_needed = FALSE;
|
|
mpt_bus_reset(adap);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* mpt_init_device_capabilities - initialize SCSI device capabilities.
|
|
*/
|
|
int
|
|
mpt_init_device_capabilities(mpt_adap_t *adap)
|
|
{
|
|
SCSIPortPage0_t *scsi_port_0 = (SCSIPortPage0_t *)adap->shared->config;
|
|
SCSIPortPage2_t *scsi_port_2 = (SCSIPortPage2_t *)adap->shared->config;
|
|
int init_capabilities;
|
|
int init_sync_period;
|
|
int targ_capabilities;
|
|
int targ_sync_period;
|
|
int targ_device_flags;
|
|
int targ;
|
|
|
|
if (!mpt_get_config_page(adap, MPI_CONFIG_PAGETYPE_SCSI_PORT, 0, 0))
|
|
{
|
|
printf("%s: Failed to get SCSI Port Page 0\n", adap->name);
|
|
return 0;
|
|
}
|
|
|
|
init_capabilities = get32(scsi_port_0->Capabilities);
|
|
|
|
init_sync_period = MPI_SCSIPORTPAGE0_CAP_GET_MIN_SYNC_PERIOD(init_capabilities);
|
|
|
|
if (!mpt_get_config_page(adap, MPI_CONFIG_PAGETYPE_SCSI_PORT, 2, 0))
|
|
{
|
|
printf("%s: Failed to get SCSI Port Page 2\n", adap->name);
|
|
return 0;
|
|
}
|
|
|
|
for (targ = 0; targ < adap->max_targets; targ++)
|
|
{
|
|
targ_sync_period = scsi_port_2->DeviceSettings[targ].SyncFactor;
|
|
targ_device_flags = get16(scsi_port_2->DeviceSettings[targ].DeviceFlags);
|
|
targ_capabilities = init_capabilities;
|
|
if (targ_sync_period == 0 || targ_sync_period > init_sync_period)
|
|
{
|
|
targ_capabilities &= ~MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK;
|
|
targ_capabilities |= targ_sync_period << MPI_SCSIDEVPAGE1_RP_SHIFT_MIN_SYNC_PERIOD;
|
|
}
|
|
if (targ_device_flags & MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE)
|
|
{
|
|
targ_capabilities &= ~MPI_SCSIDEVPAGE1_RP_WIDE;
|
|
}
|
|
adap->capabilities[targ] = targ_capabilities;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* mpt_set_device_capabilities - set SCSI device capabilities.
|
|
*/
|
|
int
|
|
mpt_set_device_capabilities(mpt_adap_t *adap, int targ)
|
|
{
|
|
SCSIDevicePage1_t *scsi_device_1 = (SCSIDevicePage1_t *)adap->shared->config;
|
|
|
|
// printf("%s: setting device capabilities\n", adap->name);
|
|
|
|
bzero(scsi_device_1, sizeof(*scsi_device_1));
|
|
|
|
/*
|
|
* Set the control bits we know we want, as well as the maximum
|
|
* synchronous offset and minimum synchronous period.
|
|
*/
|
|
scsi_device_1->RequestedParameters = set32(adap->capabilities[targ]);
|
|
|
|
if (!mpt_set_config_page(adap, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, 1, targ))
|
|
{
|
|
printf("%s: Failed to set SCSI Device Page 1 for %d\n",
|
|
adap->name, targ);
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* mpt_set_on_bus_timer - set SCSI port on-bus-timer value.
|
|
*/
|
|
int
|
|
mpt_set_on_bus_timer(mpt_adap_t *adap, int timeout)
|
|
{
|
|
SCSIPortPage1_t *scsi_port_1 = (SCSIPortPage1_t *)adap->shared->config;
|
|
U32 config;
|
|
|
|
// printf("%s: setting on-bus-timer\n", adap->name);
|
|
|
|
bzero(scsi_port_1, sizeof(*scsi_port_1));
|
|
|
|
config = adap->host_id | (1 << (adap->host_id + 16));
|
|
scsi_port_1->Configuration = set32(config);
|
|
/*
|
|
* Convert from milliseconds to 1.6 microsecond units.
|
|
*/
|
|
scsi_port_1->OnBusTimerValue = set32(timeout * 1000*10/16);
|
|
|
|
if (!mpt_set_config_page(adap, MPI_CONFIG_PAGETYPE_SCSI_PORT, 1, 0))
|
|
{
|
|
printf("%s: Failed to set SCSI Port Page 1\n", adap->name);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* mpt_get_config_page - get a configuration page.
|
|
*/
|
|
int
|
|
mpt_get_config_page(mpt_adap_t *adap, int type, int number, int address)
|
|
{
|
|
ConfigReply_t *reply = (ConfigReply_t *)adap->shared->data;
|
|
int t;
|
|
int ioc_status;
|
|
int length;
|
|
|
|
t = mpt_do_config_action(adap, MPI_CONFIG_ACTION_PAGE_HEADER, type, number, address, 0);
|
|
ioc_status = get16(reply->IOCStatus) & MPI_IOCSTATUS_MASK;
|
|
length = reply->Header.PageLength;
|
|
if (!t || ioc_status != MPI_IOCSTATUS_SUCCESS || length == 0)
|
|
{
|
|
if (ioc_status != MPI_IOCSTATUS_CONFIG_INVALID_PAGE)
|
|
{
|
|
printf("%s: Failed to get config page header\n",
|
|
adap->name);
|
|
printf("%s: IOCStatus = %04x, PageLength = %x\n",
|
|
adap->name, ioc_status, length);
|
|
printf("%s: type = %d, number = %d, address = %x\n",
|
|
adap->name, type, number, address);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
t = mpt_do_config_action(adap, MPI_CONFIG_ACTION_PAGE_READ_CURRENT, type, number, address, length);
|
|
ioc_status = get16(reply->IOCStatus) & MPI_IOCSTATUS_MASK;
|
|
if (!t || ioc_status != MPI_IOCSTATUS_SUCCESS)
|
|
{
|
|
if (ioc_status != MPI_IOCSTATUS_CONFIG_INVALID_PAGE)
|
|
{
|
|
printf("%s: Failed to get config page\n",
|
|
adap->name);
|
|
printf("%s: IOCStatus = %04x, PageLength = %x\n",
|
|
adap->name, ioc_status, length);
|
|
printf("%s: type = %d, number = %d, address = %x\n",
|
|
adap->name, type, number, address);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
* mpt_set_config_page - set a configuration page.
|
|
*/
|
|
int
|
|
mpt_set_config_page(mpt_adap_t *adap, int type, int number, int address)
|
|
{
|
|
ConfigReply_t *reply = (ConfigReply_t *)adap->shared->data;
|
|
int t;
|
|
int ioc_status;
|
|
int length;
|
|
|
|
t = mpt_do_config_action(adap, MPI_CONFIG_ACTION_PAGE_HEADER, type, number, address, 0);
|
|
ioc_status = get16(reply->IOCStatus) & MPI_IOCSTATUS_MASK;
|
|
length = reply->Header.PageLength;
|
|
if (!t || ioc_status != MPI_IOCSTATUS_SUCCESS || length == 0)
|
|
{
|
|
if (ioc_status != MPI_IOCSTATUS_CONFIG_INVALID_PAGE)
|
|
{
|
|
printf("%s: Failed to get config page header\n",
|
|
adap->name);
|
|
printf("%s: IOCStatus = %04x, PageLength = %x\n",
|
|
adap->name, ioc_status, length);
|
|
printf("%s: type = %d, number = %d, address = %x\n",
|
|
adap->name, type, number, address);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
*(ConfigPageHeader_t *)adap->shared->config= reply->Header;
|
|
|
|
t = mpt_do_config_action(adap, MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT, type, number, address, length);
|
|
ioc_status = get16(reply->IOCStatus) & MPI_IOCSTATUS_MASK;
|
|
if (!t || ioc_status != MPI_IOCSTATUS_SUCCESS)
|
|
{
|
|
if (ioc_status != MPI_IOCSTATUS_CONFIG_INVALID_PAGE)
|
|
{
|
|
printf("%s: Failed to set config page\n",
|
|
adap->name);
|
|
printf("%s: IOCStatus = %04x, PageLength = %x\n",
|
|
adap->name, ioc_status, length);
|
|
printf("%s: type = %d, number = %d, address = %x\n",
|
|
adap->name, type, number, address);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int
|
|
mpt_do_config_action(mpt_adap_t *adap, int action, int type, int number, int address, int length)
|
|
{
|
|
Config_t *request = (Config_t *)adap->shared->message;
|
|
ConfigReply_t *reply = (ConfigReply_t *)adap->shared->data;
|
|
SGESimple64_t *sge_simple = (SGESimple64_t *)&request->PageBufferSGE;
|
|
time_t limit = time(NULL) + 10;
|
|
int t;
|
|
U32 flags;
|
|
|
|
bzero(request, sizeof(*request));
|
|
bzero(reply, sizeof(*reply));
|
|
|
|
request->Function = MPI_FUNCTION_CONFIG;
|
|
request->Action = action;
|
|
request->MsgContext = set32(COMMAND_CONTEXT);
|
|
if (action == MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT ||
|
|
action == MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM)
|
|
{
|
|
request->Header = *(ConfigPageHeader_t *)adap->shared->config;
|
|
}
|
|
else
|
|
{
|
|
request->Header.PageType = type;
|
|
request->Header.PageNumber = number;
|
|
request->Header.PageLength = length;
|
|
}
|
|
request->PageAddress = set32(address);
|
|
if (length)
|
|
{
|
|
flags = (length * 4) |
|
|
MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_SIMPLE_ELEMENT |
|
|
MPI_SGE_FLAGS_LAST_ELEMENT |
|
|
MPI_SGE_FLAGS_64_BIT_ADDRESSING |
|
|
MPI_SGE_FLAGS_END_OF_BUFFER |
|
|
MPI_SGE_FLAGS_END_OF_LIST);
|
|
if (action == MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT ||
|
|
action == MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM)
|
|
{
|
|
flags |= MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_HOST_TO_IOC);
|
|
}
|
|
else
|
|
{
|
|
flags |= MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_IOC_TO_HOST);
|
|
}
|
|
sge_simple->FlagsLength = set32(flags);
|
|
sge_simple->Address.Low = set32((U32)adap->shared_ba + offsetof(mpt_shared_t, config));
|
|
#if EFI
|
|
sge_simple->Address.High = set32((U32)(adap->shared_ba >> 32));
|
|
#endif
|
|
}
|
|
else if (mpi2)
|
|
{
|
|
sge_simple->FlagsLength = set32(
|
|
MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_SIMPLE_ELEMENT |
|
|
MPI_SGE_FLAGS_LAST_ELEMENT |
|
|
MPI_SGE_FLAGS_64_BIT_ADDRESSING |
|
|
MPI_SGE_FLAGS_END_OF_BUFFER |
|
|
MPI_SGE_FLAGS_END_OF_LIST));
|
|
}
|
|
|
|
|
|
if (mpt_verify_operational(adap))
|
|
{
|
|
logMptCommandReq(adap->port, request, sizeof(*request));
|
|
|
|
t = mpt_issue_config_and_wait(adap, 10);
|
|
|
|
logMptCommandRep(adap->port, request, sizeof(*request), reply, sizeof(*reply), t);
|
|
|
|
if (!t)
|
|
{
|
|
if ((get16(reply->IOCStatus) & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_CONFIG_INVALID_PAGE)
|
|
{
|
|
printf("%s: mpt_issue_config_and_wait / Config failed!\n", adap->name);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
if (mpt_verify_ready(adap))
|
|
{
|
|
logMptCommandReq(adap->port, request, sizeof(*request));
|
|
|
|
if (!mpt_send_message(adap, sizeof(*request), limit))
|
|
{
|
|
printf("%s: mpt_send_message / Config failed\n", adap->name);
|
|
return 0;
|
|
}
|
|
|
|
t = mpt_receive_data(adap, sizeof(*reply), limit);
|
|
|
|
logMptCommandRep(adap->port, request, sizeof(*request), reply, sizeof(*reply), t);
|
|
|
|
if (!t)
|
|
{
|
|
if ((get16(reply->IOCStatus) & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_CONFIG_INVALID_PAGE)
|
|
{
|
|
printf("%s: mpt_receive_data / Config failed\n", adap->name);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void
|
|
mpt_bus_reset(mpt_adap_t *adap)
|
|
{
|
|
SCSITaskMgmt_t *request = (SCSITaskMgmt_t *)adap->shared->message;
|
|
time_t limit = time(NULL) + 10;
|
|
|
|
// printf("%s: sending SCSITaskMgmt (ResetBus)\n", adap->name);
|
|
|
|
/*
|
|
* Use a SCSI Task Management request to reset the bus.
|
|
*/
|
|
bzero(request, sizeof(*request));
|
|
|
|
request->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
|
|
request->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
|
|
request->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIP_RESET_OPTION;
|
|
|
|
logMptCommandReq(adap->port, request, sizeof(*request));
|
|
|
|
if (!mpt_send_message(adap, sizeof(*request), limit))
|
|
{
|
|
printf("%s: mpt_send_message / SCSITaskMgmt failed\n", adap->name);
|
|
adap->restart_needed = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
mpt_interrupt(mpt_adap_t *adap)
|
|
{
|
|
U32 context;
|
|
U32 reply_ba;
|
|
MPIDefaultReply_t *reply;
|
|
U32 doorbell;
|
|
int state;
|
|
|
|
// printf("mpt_interrupt called\n");
|
|
|
|
if (mpi2)
|
|
{
|
|
mpt2_interrupt(adap);
|
|
return;
|
|
}
|
|
|
|
if (adap->hrsm_capable)
|
|
{
|
|
if (adap->hrsm_value == adap->shared->hrsm_value)
|
|
return;
|
|
adap->hrsm_value = adap->shared->hrsm_value;
|
|
}
|
|
|
|
doorbell = rl(DOORBELL);
|
|
state = doorbell & MPI_IOC_STATE_MASK;
|
|
if (state != MPI_IOC_STATE_OPERATIONAL)
|
|
{
|
|
if (state == MPI_IOC_STATE_FAULT)
|
|
{
|
|
printf("%s: MPT Firmware Fault, code %04x\n",
|
|
adap->name, doorbell & MPI_DOORBELL_DATA_MASK);
|
|
if (wFlag)
|
|
fprintf(logFile, "%s: MPT Firmware Fault, code %04x\n",
|
|
adap->name, doorbell & MPI_DOORBELL_DATA_MASK);
|
|
|
|
printf("\nHit Enter to continue ");
|
|
|
|
getYesNoAnswer(0);
|
|
|
|
printf("\n");
|
|
}
|
|
adap->restart_needed = TRUE;
|
|
}
|
|
|
|
while ((context = rl(REPLY_QUEUE)) != 0xffffffff)
|
|
{
|
|
if (context & MPI_CONTEXT_REPLY_A_BIT)
|
|
{
|
|
reply_ba = context << 1;
|
|
reply = (MPIDefaultReply_t *)((U8 *)adap->shared + reply_ba - (U32)adap->shared_ba);
|
|
if (mpt_handle_reply(adap, reply, reply_ba))
|
|
wl(REPLY_QUEUE, reply_ba);
|
|
continue;
|
|
}
|
|
if (context == PASS_THRU_CONTEXT)
|
|
{
|
|
if (adap->command_active == TRUE)
|
|
{
|
|
SCSIIOReply_t *scsiRep = (SCSIIOReply_t *)adap->shared->data;
|
|
|
|
adap->command_active = FALSE;
|
|
bzero(scsiRep, sizeof(*scsiRep));
|
|
}
|
|
continue;
|
|
}
|
|
printf("%s: Invalid reply, Context = %08x\n", adap->name, reply);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
mpt2_interrupt(mpt_adap_t *adap)
|
|
{
|
|
int index;
|
|
Mpi2DefaultReplyDescriptor_t *reply_desc;
|
|
int reply_type;
|
|
int count;
|
|
|
|
index = adap->post_index;
|
|
count = 0;
|
|
while (TRUE)
|
|
{
|
|
reply_desc = &adap->shared->post_queue[index];
|
|
reply_type = reply_desc->ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
|
|
if (reply_type == MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS)
|
|
{
|
|
mpt2_handle_scsi_io_success(adap, reply_desc);
|
|
}
|
|
else if (reply_type == MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY)
|
|
{
|
|
mpt2_handle_address_reply(adap, reply_desc);
|
|
}
|
|
else if (reply_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
printf("%s: Invalid reply, ReplyType = %x\n", adap->name, reply_type);
|
|
}
|
|
reply_desc->ReplyFlags = MPI2_RPY_DESCRIPT_FLAGS_UNUSED;
|
|
index++;
|
|
if (index == REPLY_POST_SIZE)
|
|
index = 0;
|
|
count++;
|
|
}
|
|
|
|
if (count)
|
|
{
|
|
adap->post_index = index;
|
|
wl2(REPLY_POST_HOST_INDEX, index);
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
mpt_handle_reply(mpt_adap_t *adap, MPIDefaultReply_t *reply, U32 reply_ba)
|
|
{
|
|
U32 context;
|
|
EventNotificationReply_t *event;
|
|
EventDataScsi_t *ed_scsi;
|
|
EventAckReply_t *event_ack;
|
|
int targ;
|
|
int repost;
|
|
|
|
repost = 1;
|
|
context = get32(reply->MsgContext);
|
|
|
|
if (get16(reply->IOCStatus) & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
|
|
{
|
|
printf("%s: Function = %02x, IOCStatus = %04x, IOCLogInfo = %08x\n",
|
|
adap->name, reply->Function, get16(reply->IOCStatus),
|
|
get32(reply->IOCLogInfo));
|
|
}
|
|
|
|
if (context == PASS_THRU_CONTEXT)
|
|
{
|
|
if (adap->command_active == TRUE)
|
|
{
|
|
adap->command_active = FALSE;
|
|
bcopy(reply, adap->shared->data, reply->MsgLength * 4);
|
|
}
|
|
return repost;
|
|
}
|
|
|
|
switch (reply->Function)
|
|
{
|
|
case MPI_FUNCTION_CONFIG:
|
|
if (adap->config_active == TRUE)
|
|
{
|
|
adap->config_active = FALSE;
|
|
bcopy(reply, adap->shared->data, reply->MsgLength * 4);
|
|
}
|
|
break;
|
|
case MPI_FUNCTION_EVENT_NOTIFICATION:
|
|
logMptCommandRep(adap->port, NULL, 0, reply, sizeof(*reply), 1);
|
|
event = (EventNotificationReply_t *)reply;
|
|
switch (get32(event->Event))
|
|
{
|
|
case MPI_EVENT_NONE:
|
|
break;
|
|
case MPI_EVENT_STATE_CHANGE:
|
|
adap->restart_needed = TRUE;
|
|
break;
|
|
case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
|
|
ed_scsi = (EventDataScsi_t *)event->Data;
|
|
targ = ed_scsi->TargetID;
|
|
printf("%s: ON BUS TIMER EXPIRED for SCSI target %d\n", adap->name, targ);
|
|
adap->bus_reset_needed = TRUE;
|
|
break;
|
|
}
|
|
if (event->AckRequired)
|
|
{
|
|
_U32 t1;
|
|
_U32 t2;
|
|
EventAck_t *event_ack;
|
|
|
|
t1 = event->Event;
|
|
t2 = event->EventContext;
|
|
/*
|
|
* Use the EventNotify reply as the EventAck command.
|
|
*/
|
|
event_ack = (EventAck_t *)event;
|
|
bzero(event_ack, sizeof(*event_ack));
|
|
event_ack->Function = MPI_FUNCTION_EVENT_ACK;
|
|
event_ack->MsgContext = set32(reply_ba);
|
|
event_ack->Event = t1;
|
|
event_ack->EventContext = t2;
|
|
wl(REQUEST_QUEUE, get32(event_ack->MsgContext));
|
|
/*
|
|
* Signal that the reply should not be given back to
|
|
* the IOC yet, since it's being used as the EventAck
|
|
* command right now.
|
|
*/
|
|
repost = 0;
|
|
}
|
|
break;
|
|
case MPI_FUNCTION_EVENT_ACK:
|
|
event_ack = (EventAckReply_t *)reply;
|
|
wl(REPLY_QUEUE, get32(event_ack->MsgContext));
|
|
break;
|
|
default:
|
|
printf("%s: Invalid reply, Function = %02x, IOCStatus = %04x\n",
|
|
adap->name, reply->Function, get16(reply->IOCStatus));
|
|
#if 1
|
|
{
|
|
int i;
|
|
U32 *p = (U32 *)reply;
|
|
|
|
for (i = 0; i < reply->MsgLength; i++)
|
|
printf("reply[%02x] = %08x\n", i*4, get32x(p[i]));
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
return repost;
|
|
}
|
|
|
|
|
|
void
|
|
mpt2_handle_scsi_io_success(mpt_adap_t *adap, Mpi2DefaultReplyDescriptor_t *reply_desc)
|
|
{
|
|
Mpi2SCSIIOSuccessReplyDescriptor_t *scsi_io_success;
|
|
U32 context;
|
|
|
|
scsi_io_success = (Mpi2SCSIIOSuccessReplyDescriptor_t *)reply_desc;
|
|
context = adap->msg_context;
|
|
if (get16(scsi_io_success->SMID) == 1)
|
|
adap->msg_context = 0;
|
|
|
|
if (context == PASS_THRU_CONTEXT)
|
|
{
|
|
if (adap->command_active == TRUE)
|
|
{
|
|
Mpi2SCSIIOReply_t *scsiRep = (Mpi2SCSIIOReply_t *)adap->shared->data;
|
|
|
|
adap->command_active = FALSE;
|
|
bzero(scsiRep, sizeof(*scsiRep));
|
|
}
|
|
return;
|
|
}
|
|
printf("%s: Invalid SCSI IO SUCCESS reply, Context = %08x\n", adap->name, context);
|
|
}
|
|
|
|
|
|
void
|
|
mpt2_handle_address_reply(mpt_adap_t *adap, Mpi2DefaultReplyDescriptor_t *reply_desc)
|
|
{
|
|
Mpi2AddressReplyDescriptor_t *address_reply;
|
|
MPI2DefaultReply_t *reply;
|
|
U32 context;
|
|
U32 reply_ba;
|
|
int index;
|
|
|
|
address_reply = (Mpi2AddressReplyDescriptor_t *)reply_desc;
|
|
|
|
reply_ba = get32(address_reply->ReplyFrameAddress);
|
|
reply = (MPI2DefaultReply_t *)((U8 *)adap->shared + reply_ba - (U32)adap->shared_ba);
|
|
context = adap->msg_context;
|
|
if (get16(address_reply->SMID) == 1)
|
|
adap->msg_context = 0;
|
|
|
|
if (get16(reply->IOCStatus) & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
|
|
{
|
|
printf("%s: Function = %02x, IOCStatus = %04x, IOCLogInfo = %08x\n",
|
|
adap->name, reply->Function, get16(reply->IOCStatus),
|
|
get32(reply->IOCLogInfo));
|
|
}
|
|
|
|
if (context == PASS_THRU_CONTEXT)
|
|
{
|
|
if (adap->command_active == TRUE)
|
|
{
|
|
adap->command_active = FALSE;
|
|
bcopy(reply, adap->shared->data, reply->MsgLength * 4);
|
|
}
|
|
goto repost;
|
|
}
|
|
|
|
switch (reply->Function)
|
|
{
|
|
case MPI2_FUNCTION_CONFIG:
|
|
if (adap->config_active == TRUE)
|
|
{
|
|
adap->config_active = FALSE;
|
|
bcopy(reply, adap->shared->data, reply->MsgLength * 4);
|
|
}
|
|
break;
|
|
default:
|
|
printf("%s: Invalid reply, Function = %02x, IOCStatus = %04x\n",
|
|
adap->name, reply->Function, get16(reply->IOCStatus));
|
|
#if 1
|
|
{
|
|
int i;
|
|
U32 *p = (U32 *)reply;
|
|
|
|
for (i = 0; i < reply->MsgLength; i++)
|
|
printf("reply[%02x] = %08x\n", i*4, get32x(p[i]));
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
repost:
|
|
index = adap->free_index;
|
|
adap->shared->free_queue[index] = reply_ba;
|
|
index++;
|
|
if (index == REPLY_FREE_SIZE)
|
|
index = 0;
|
|
adap->free_index = index;
|
|
wl2(REPLY_FREE_HOST_INDEX, index);
|
|
}
|
|
|
|
|
|
int mpt_fwdownloadboot(mpt_adap_t *adap)
|
|
{
|
|
U16 deviceId = adap->device_id;
|
|
MpiFwHeader_t *fwHeader;
|
|
MpiExtImageHeader_t *extImageHeader;
|
|
U32 *image;
|
|
U8 *nextImage;
|
|
U32 addr;
|
|
U32 size;
|
|
U32 next;
|
|
U32 data;
|
|
U32 resetAddr;
|
|
U32 resetData;
|
|
int t;
|
|
|
|
if (adap->fw_image == NULL)
|
|
{
|
|
char name[256];
|
|
int n;
|
|
|
|
if (adap->fw_image_asked == TRUE)
|
|
return 0;
|
|
|
|
adap->fw_image_asked = TRUE;
|
|
|
|
printf("\nThe firmware on this %s appears broken!\n", adap->port->chipNameRev);
|
|
printf("A valid firmware image is required to make this chip operational...\n\n");
|
|
|
|
n = getFileName(name, sizeof name, stdin, "firmware", 99);
|
|
if (n > 0)
|
|
{
|
|
if (readFile(name, &adap->fw_image, &adap->fw_image_size) != 1)
|
|
{
|
|
printf("\nThe firmware image could not be read\n");
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printf("\nThe chip cannot be made operational\n");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (deviceId == MPI_MANUFACTPAGE_DEVICEID_FC909 ||
|
|
deviceId == MPI_MANUFACTPAGE_DEVICEID_FC919 ||
|
|
deviceId == MPI_MANUFACTPAGE_DEVICEID_FC929)
|
|
{
|
|
return mpt_directdownload(adap);
|
|
}
|
|
|
|
wl(WRITE_SEQUENCE, 0);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_KEY_VALUE_MASK);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_1ST_KEY_VALUE);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_2ND_KEY_VALUE);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_3RD_KEY_VALUE);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_4TH_KEY_VALUE);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_5TH_KEY_VALUE);
|
|
|
|
wl(DIAGNOSTIC, MPI_DIAG_DISABLE_ARM |
|
|
MPI_DIAG_PREVENT_IOC_BOOT |
|
|
MPI_DIAG_CLEAR_FLASH_BAD_SIG);
|
|
DELAY(100);
|
|
|
|
if (deviceId == MPI_MANUFACTPAGE_DEVICEID_FC949E)
|
|
{
|
|
wl(DIAGNOSTIC, MPI_DIAG_DISABLE_ARM |
|
|
MPI_DIAG_PREVENT_IOC_BOOT |
|
|
MPI_DIAG_CLEAR_FLASH_BAD_SIG |
|
|
MPI_DIAG_RW_ENABLE);
|
|
|
|
wlio(DIAG_RW_ADDRESS, 0x40100064);
|
|
data = rlio(DIAG_RW_DATA);
|
|
|
|
wlio(DIAG_RW_ADDRESS, 0x40100064);
|
|
wlio(DIAG_RW_DATA, data | 0x20000);
|
|
|
|
DELAY(100);
|
|
}
|
|
|
|
wl(DIAGNOSTIC, MPI_DIAG_DISABLE_ARM |
|
|
MPI_DIAG_PREVENT_IOC_BOOT |
|
|
MPI_DIAG_RESET_ADAPTER);
|
|
DELAY(50000);
|
|
|
|
wl(WRITE_SEQUENCE, 0);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_KEY_VALUE_MASK);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_1ST_KEY_VALUE);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_2ND_KEY_VALUE);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_3RD_KEY_VALUE);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_4TH_KEY_VALUE);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_5TH_KEY_VALUE);
|
|
|
|
wl(DIAGNOSTIC, MPI_DIAG_DISABLE_ARM |
|
|
MPI_DIAG_PREVENT_IOC_BOOT |
|
|
MPI_DIAG_CLEAR_FLASH_BAD_SIG |
|
|
MPI_DIAG_RW_ENABLE);
|
|
|
|
if (deviceId == MPI_MANUFACTPAGE_DEVICEID_FC949E)
|
|
{
|
|
wlio(DIAG_RW_ADDRESS, 0x40100064);
|
|
wlio(DIAG_RW_DATA, data);
|
|
}
|
|
|
|
fwHeader = (MpiFwHeader_t *)adap->fw_image;
|
|
|
|
image = (U32 *)fwHeader;
|
|
|
|
addr = get32(fwHeader->LoadStartAddress);
|
|
size = get32(fwHeader->ImageSize);
|
|
|
|
next = get32(fwHeader->NextImageHeaderOffset);
|
|
|
|
resetAddr = get32(fwHeader->IopResetRegAddr);
|
|
resetData = get32(fwHeader->IopResetVectorValue);
|
|
|
|
while (next != 0)
|
|
{
|
|
nextImage = (U8 *)fwHeader + next;
|
|
|
|
extImageHeader = (MpiExtImageHeader_t *)nextImage;
|
|
|
|
if (extImageHeader->ImageType == MPI_EXT_IMAGE_TYPE_BOOTLOADER)
|
|
{
|
|
printf("Found a BootLoader, using only that part of the image!\n");
|
|
|
|
adap->bootloader = TRUE;
|
|
|
|
image = (U32 *)extImageHeader;
|
|
|
|
addr = get32(extImageHeader->LoadStartAddress);
|
|
size = get32(extImageHeader->ImageSize);
|
|
|
|
next = 0;
|
|
|
|
resetData = addr + sizeof(MpiExtImageHeader_t);
|
|
|
|
break;
|
|
}
|
|
|
|
next = get32(extImageHeader->NextImageHeaderOffset);
|
|
}
|
|
|
|
if (addr == get32(fwHeader->LoadStartAddress) &&
|
|
size == get32(fwHeader->ImageSize))
|
|
{
|
|
next = get32(fwHeader->NextImageHeaderOffset);
|
|
}
|
|
|
|
while (1)
|
|
{
|
|
wlio(DIAG_RW_ADDRESS, addr);
|
|
|
|
while (size)
|
|
{
|
|
data = *image++;
|
|
|
|
wlio(DIAG_RW_DATA, data);
|
|
|
|
size -= 4;
|
|
}
|
|
|
|
if (next == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
nextImage = (U8 *)fwHeader + next;
|
|
|
|
extImageHeader = (MpiExtImageHeader_t *)nextImage;
|
|
|
|
image = (U32 *)extImageHeader;
|
|
|
|
addr = get32(extImageHeader->LoadStartAddress);
|
|
size = get32(extImageHeader->ImageSize);
|
|
|
|
next = get32(extImageHeader->NextImageHeaderOffset);
|
|
}
|
|
|
|
wlio(DIAG_RW_ADDRESS, resetAddr);
|
|
wlio(DIAG_RW_DATA, resetData);
|
|
|
|
if (deviceId == MPI_MANUFACTPAGE_DEVID_53C1030)
|
|
{
|
|
wlio(DIAG_RW_ADDRESS, 0x3f000000);
|
|
data = rlio(DIAG_RW_DATA);
|
|
|
|
data |= 0x40000000;
|
|
|
|
wlio(DIAG_RW_ADDRESS, 0x3f000000);
|
|
wlio(DIAG_RW_DATA, data);
|
|
}
|
|
|
|
if (deviceId == MPI_MANUFACTPAGE_DEVICEID_FC919X ||
|
|
deviceId == MPI_MANUFACTPAGE_DEVICEID_FC929X)
|
|
{
|
|
wlio(DIAG_RW_ADDRESS, 0x3e000000);
|
|
data = rlio(DIAG_RW_DATA);
|
|
}
|
|
|
|
if (deviceId == MPI_MANUFACTPAGE_DEVICEID_FC939X ||
|
|
deviceId == MPI_MANUFACTPAGE_DEVICEID_FC949X ||
|
|
deviceId == MPI_MANUFACTPAGE_DEVICEID_FC949E)
|
|
{
|
|
wlio(DIAG_RW_ADDRESS, 0x3d000000);
|
|
data = rlio(DIAG_RW_DATA);
|
|
}
|
|
|
|
if (adap->bootloader)
|
|
{
|
|
wl(DIAGNOSTIC, MPI_DIAG_DISABLE_ARM |
|
|
MPI_DIAG_CLEAR_FLASH_BAD_SIG);
|
|
DELAY(100);
|
|
|
|
wl(DIAGNOSTIC, 0);
|
|
DELAY(100);
|
|
|
|
sleep(1);
|
|
}
|
|
|
|
wl(DIAGNOSTIC, MPI_DIAG_DISABLE_ARM |
|
|
MPI_DIAG_CLEAR_FLASH_BAD_SIG);
|
|
DELAY(100);
|
|
|
|
wl(DIAGNOSTIC, 0);
|
|
DELAY(100);
|
|
|
|
t = mpt_wait_for_ready(adap);
|
|
|
|
if (wFlag)
|
|
fprintf(logFile, "%s: Firmware Download Boot: %s\n",
|
|
adap->name, t ? "PASS" : "FAIL");
|
|
|
|
if (t)
|
|
return 1;
|
|
|
|
printf("\n%s: FWDownloadBoot failed!\n", adap->name);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
mpt_directdownload(mpt_adap_t *adap)
|
|
{
|
|
U16 deviceId = adap->device_id;
|
|
U32 mask = adap->diagmem_size - 1;
|
|
MpiFwHeader_t *fwHeader;
|
|
U32 *image;
|
|
U32 addr;
|
|
U32 size;
|
|
U32 data;
|
|
int t;
|
|
|
|
wl(WRITE_SEQUENCE, 0);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_KEY_VALUE_MASK);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_1ST_KEY_VALUE);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_2ND_KEY_VALUE);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_3RD_KEY_VALUE);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_4TH_KEY_VALUE);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_5TH_KEY_VALUE);
|
|
|
|
wl(DIAGNOSTIC, MPI_DIAG_DISABLE_ARM);
|
|
DELAY(100);
|
|
|
|
/* If FlashBadSig is set, the download doesn't seem to work if we reset
|
|
* the chip here.
|
|
*
|
|
* If FlashBadSig isn't set, the download doesn't seem to work if we
|
|
* don't reset the chip here.
|
|
*/
|
|
data = rl(DIAGNOSTIC);
|
|
if (!(data & MPI_DIAG_FLASH_BAD_SIG))
|
|
{
|
|
wl(DIAGNOSTIC, MPI_DIAG_DISABLE_ARM | MPI_DIAG_RESET_ADAPTER);
|
|
DELAY(50000);
|
|
|
|
wl(WRITE_SEQUENCE, 0);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_KEY_VALUE_MASK);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_1ST_KEY_VALUE);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_2ND_KEY_VALUE);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_3RD_KEY_VALUE);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_4TH_KEY_VALUE);
|
|
wl(WRITE_SEQUENCE, MPI_WRSEQ_5TH_KEY_VALUE);
|
|
}
|
|
|
|
wl(DIAGNOSTIC, MPI_DIAG_DISABLE_ARM | MPI_DIAG_MEM_ENABLE);
|
|
|
|
addr = 0x50004;
|
|
rldiag(addr, data);
|
|
data &= ~0x80000000;
|
|
wldiag(addr, data);
|
|
|
|
if (deviceId == MPI_MANUFACTPAGE_DEVICEID_FC929)
|
|
{
|
|
addr = 0x51004;
|
|
rldiag(addr, data);
|
|
data &= ~0x80000000;
|
|
wldiag(addr, data);
|
|
}
|
|
|
|
if (rl(DIAGNOSTIC) & MPI_DIAG_FLASH_BAD_SIG)
|
|
{
|
|
addr = 0x40000;
|
|
rldiag(addr, data);
|
|
data |= 0x40000000;
|
|
wldiag(addr, data);
|
|
}
|
|
|
|
fwHeader = (MpiFwHeader_t *)adap->fw_image;
|
|
|
|
image = (U32 *)fwHeader;
|
|
|
|
addr = get32(fwHeader->LoadStartAddress);
|
|
size = get32(fwHeader->ImageSize);
|
|
|
|
while (size)
|
|
{
|
|
data = *image++;
|
|
|
|
wldiag(addr, data);
|
|
|
|
addr += 4;
|
|
size -= 4;
|
|
}
|
|
|
|
addr = get32(fwHeader->IopResetRegAddr);
|
|
data = get32(fwHeader->IopResetVectorValue);
|
|
|
|
wldiag(addr, data);
|
|
|
|
addr = 0x40000;
|
|
rldiag(addr, data);
|
|
data |= 0x40000000;
|
|
wldiag(addr, data);
|
|
|
|
wl(DIAGNOSTIC, 0);
|
|
DELAY(100);
|
|
|
|
t = mpt_wait_for_ready(adap);
|
|
|
|
if (wFlag)
|
|
fprintf(logFile, "%s: Firmware Direct Download: %s\n",
|
|
adap->name, t ? "PASS" : "FAIL");
|
|
|
|
if (t)
|
|
return 1;
|
|
|
|
printf("\n%s: DirectDownload failed!\n", adap->name);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* vi: set sw=4 ts=4 sts=4 et :iv */
|