Make aacraid(4) working on ASR8805 & ASR8402 in particular. This patch

has been in the PR system for 5 months and then on reviews for another 5.
Nobody came with any cases where it fails, while many people cried for
it to be commited & merged.

PR:		209468
Submitted by:	Prasad B M <prasad.munirathnam@microsemi.com>
Reported by:	Steven Peterson <scp@mainstream.net>
Approved by:	scottl
MFC after:	1 month
Differential Revision:	https://reviews.freebsd.org/D18408
This commit is contained in:
Maxim Sobolev 2019-05-22 04:51:08 +00:00
parent d3f77d0afe
commit 4f1dfaba98
4 changed files with 106 additions and 72 deletions

View File

@ -264,7 +264,7 @@ aacraid_attach(struct aac_softc *sc)
/*
* Check that the firmware on the card is supported.
*/
sc->msi_enabled = FALSE;
sc->msi_enabled = sc->msi_tupelo = FALSE;
if ((error = aac_check_firmware(sc)) != 0)
return(error);
@ -284,8 +284,8 @@ aacraid_attach(struct aac_softc *sc)
*/
if ((error = aac_alloc(sc)) != 0)
return(error);
aac_define_int_mode(sc);
if (!(sc->flags & AAC_FLAGS_SYNC_MODE)) {
aac_define_int_mode(sc);
if ((error = aac_init(sc)) != 0)
return(error);
}
@ -728,7 +728,7 @@ aacraid_free(struct aac_softc *sc)
else
break;
}
if (sc->msi_enabled)
if (sc->msi_enabled || sc->msi_tupelo)
pci_release_msi(sc->aac_dev);
/* destroy data-transfer DMA tag */
@ -1316,6 +1316,9 @@ aacraid_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "nseg %d", nseg);
mtx_assert(&sc->aac_io_lock, MA_OWNED);
if ((sc->flags & AAC_FLAGS_SYNC_MODE) && sc->aac_sync_cm)
return;
/* copy into the FIB */
if (cm->cm_sgtable != NULL) {
if (fib->Header.Command == RawIo2) {
@ -1433,11 +1436,14 @@ aacraid_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error)
cm->cm_flags |= AAC_CMD_MAPPED;
if (sc->flags & AAC_FLAGS_SYNC_MODE) {
if (cm->cm_flags & AAC_CMD_WAIT) {
aacraid_sync_command(sc, AAC_MONKER_SYNCFIB,
cm->cm_fibphys, 0, 0, 0, NULL, NULL);
} else if (sc->flags & AAC_FLAGS_SYNC_MODE) {
u_int32_t wait = 0;
aacraid_sync_command(sc, AAC_MONKER_SYNCFIB, cm->cm_fibphys, 0, 0, 0, &wait, NULL);
} else if (cm->cm_flags & AAC_CMD_WAIT) {
aacraid_sync_command(sc, AAC_MONKER_SYNCFIB, cm->cm_fibphys, 0, 0, 0, NULL, NULL);
sc->aac_sync_cm = cm;
aacraid_sync_command(sc, AAC_MONKER_SYNCFIB,
cm->cm_fibphys, 0, 0, 0, &wait, NULL);
} else {
int count = 10000000L;
while (AAC_SEND_COMMAND(sc, cm) != 0) {
@ -1617,6 +1623,7 @@ aac_check_firmware(struct aac_softc *sc)
options = AAC_GET_MAILBOX(sc, 1);
atu_size = AAC_GET_MAILBOX(sc, 2);
sc->supported_options = options;
sc->doorbell_mask = AAC_GET_MAILBOX(sc, 3);
if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
(sc->flags & AAC_FLAGS_NO4GB) == 0)
@ -1631,13 +1638,13 @@ aac_check_firmware(struct aac_softc *sc)
sc->flags |= AAC_FLAGS_SG_64BIT;
}
if (sc->aac_if.aif_send_command) {
if ((options & AAC_SUPPORTED_NEW_COMM_TYPE3) ||
(options & AAC_SUPPORTED_NEW_COMM_TYPE4))
sc->flags |= AAC_FLAGS_NEW_COMM | AAC_FLAGS_NEW_COMM_TYPE34;
if (options & AAC_SUPPORTED_NEW_COMM_TYPE2)
sc->flags |= AAC_FLAGS_NEW_COMM | AAC_FLAGS_NEW_COMM_TYPE2;
else if (options & AAC_SUPPORTED_NEW_COMM_TYPE1)
sc->flags |= AAC_FLAGS_NEW_COMM | AAC_FLAGS_NEW_COMM_TYPE1;
else if (options & AAC_SUPPORTED_NEW_COMM_TYPE2)
sc->flags |= AAC_FLAGS_NEW_COMM | AAC_FLAGS_NEW_COMM_TYPE2;
else if ((options & AAC_SUPPORTED_NEW_COMM_TYPE3) ||
(options & AAC_SUPPORTED_NEW_COMM_TYPE4))
sc->flags |= AAC_FLAGS_NEW_COMM | AAC_FLAGS_NEW_COMM_TYPE34;
}
if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE)
sc->flags |= AAC_FLAGS_ARRAY_64BIT;
@ -1851,8 +1858,30 @@ aac_define_int_mode(struct aac_softc *sc)
dev = sc->aac_dev;
if (sc->flags & AAC_FLAGS_SYNC_MODE) {
device_printf(dev, "using line interrupts\n");
sc->aac_max_msix = 1;
sc->aac_vector_cap = sc->aac_max_fibs;
return;
}
/* max. vectors from AAC_MONKER_GETCOMMPREF */
if (sc->aac_max_msix == 0) {
if (sc->aac_hwif == AAC_HWIF_SRC) {
msi_count = 1;
if ((error = pci_alloc_msi(dev, &msi_count)) != 0) {
device_printf(dev, "alloc msi failed - err=%d; "
"will use INTx\n", error);
pci_release_msi(dev);
} else {
sc->msi_tupelo = TRUE;
}
}
if (sc->msi_tupelo)
device_printf(dev, "using MSI interrupts\n");
else
device_printf(dev, "using line interrupts\n");
sc->aac_max_msix = 1;
sc->aac_vector_cap = sc->aac_max_fibs;
return;
@ -1958,7 +1987,7 @@ aac_setup_intr(struct aac_softc *sc)
void *tag;
msi_count = sc->aac_max_msix;
rid = (sc->msi_enabled ? 1:0);
rid = ((sc->msi_enabled || sc->msi_tupelo)? 1:0);
for (i = 0; i < msi_count; i++, rid++) {
if ((res = bus_alloc_resource_any(sc->aac_dev,SYS_RES_IRQ, &rid,
@ -2854,14 +2883,14 @@ aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg)
fib = cm->cm_fib;
srbcmd = (struct aac_srb *)fib->data;
if ((error = copyin((void *)&user_srb->data_len, &fibsize,
sizeof (u_int32_t)) != 0))
if ((error = copyin((void *)&user_srb->data_len, &fibsize,
sizeof (u_int32_t))) != 0)
goto out;
if (fibsize > (sc->aac_max_fib_size-sizeof(struct aac_fib_header))) {
error = EINVAL;
goto out;
}
if ((error = copyin((void *)user_srb, srbcmd, fibsize) != 0))
if ((error = copyin((void *)user_srb, srbcmd, fibsize)) != 0)
goto out;
srbcmd->function = 0; /* SRBF_ExecuteScsi */
@ -2895,13 +2924,10 @@ aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg)
srb_sg_bytecount = sg.SgByteCount;
srb_sg_address = sg.SgAddress;
if (srb_sg_address > 0xffffffffull &&
!(sc->flags & AAC_FLAGS_SG_64BIT))
#endif
{
error = EINVAL;
goto out;
}
#else
error = EINVAL;
goto out;
#endif
} else {
error = EINVAL;
goto out;
@ -3701,7 +3727,7 @@ aac_get_bus_info(struct aac_softc *sc)
caminf->TargetsPerBus = businfo.TargetsPerBus;
caminf->BusNumber = i+1;
caminf->BusType = PASSTHROUGH_BUS;
caminf->InitiatorBusId = businfo.InitiatorBusId[i];
caminf->InitiatorBusId = -1;
caminf->aac_sc = sc;
caminf->sim_dev = child;
caminf->aac_cam = NULL;
@ -3745,7 +3771,7 @@ aac_reset_adapter(struct aac_softc *sc)
struct aac_fib *fib;
struct aac_pause_command *pc;
u_int32_t status, reset_mask, waitCount, max_msix_orig;
int msi_enabled_orig;
int ret, msi_enabled_orig;
fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
mtx_assert(&sc->aac_io_lock, MA_OWNED);
@ -3804,50 +3830,61 @@ aac_reset_adapter(struct aac_softc *sc)
AAC_MEM0_SETREG4(sc, AAC_IRCSR, AAC_IRCSR_CORES_RST);
/* We need to wait for 5 seconds before accessing the MU again
* 10000 * 100us = 1000,000us = 1000ms = 1s
* 10000 * 100us = 1000,000us = 1000ms = 1s
*/
waitCount = 5 * 10000;
while (waitCount) {
DELAY(100); /* delay 100 microseconds */
waitCount--;
}
} else if ((aacraid_sync_command(sc,
AAC_IOP_RESET_ALWAYS, 0, 0, 0, 0, &status, &reset_mask)) != 0) {
/* call IOP_RESET for older firmware */
if ((aacraid_sync_command(sc,
AAC_IOP_RESET, 0, 0, 0, 0, &status, NULL)) != 0) {
} else {
ret = aacraid_sync_command(sc, AAC_IOP_RESET_ALWAYS,
0, 0, 0, 0, &status, &reset_mask);
if (ret && !sc->doorbell_mask) {
/* call IOP_RESET for older firmware */
if ((aacraid_sync_command(sc, AAC_IOP_RESET, 0,0,0,0,
&status, NULL)) != 0) {
if (status == AAC_SRB_STS_INVALID_REQUEST) {
device_printf(sc->aac_dev,
"IOP_RESET not supported\n");
} else {
/* probably timeout */
device_printf(sc->aac_dev,
"IOP_RESET failed\n");
}
if (status == AAC_SRB_STS_INVALID_REQUEST)
device_printf(sc->aac_dev, "IOP_RESET not supported\n");
else
/* probably timeout */
device_printf(sc->aac_dev, "IOP_RESET failed\n");
/* unwind aac_shutdown() */
aac_alloc_sync_fib(sc, &fib);
pc = (struct aac_pause_command *)&fib->data[0];
pc->Command = VM_ContainerConfig;
pc->Type = CT_PAUSE_IO;
pc->Timeout = 1;
pc->Min = 1;
pc->NoRescan = 1;
/* unwind aac_shutdown() */
aac_alloc_sync_fib(sc, &fib);
pc = (struct aac_pause_command *)&fib->data[0];
pc->Command = VM_ContainerConfig;
pc->Type = CT_PAUSE_IO;
pc->Timeout = 1;
pc->Min = 1;
pc->NoRescan = 1;
(void) aac_sync_fib(sc, ContainerCommand, 0,
fib, sizeof (struct aac_pause_command));
aac_release_sync_fib(sc);
(void) aac_sync_fib(sc, ContainerCommand, 0, fib,
sizeof (struct aac_pause_command));
aac_release_sync_fib(sc);
goto finish;
goto finish;
}
} else if (sc->doorbell_mask) {
ret = 0;
reset_mask = sc->doorbell_mask;
}
} else if (sc->aac_support_opt2 & AAC_SUPPORTED_DOORBELL_RESET) {
AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, reset_mask);
/*
* We need to wait for 5 seconds before accessing the doorbell
* again, 10000 * 100us = 1000,000us = 1000ms = 1s
*/
waitCount = 5 * 10000;
while (waitCount) {
DELAY(100); /* delay 100 microseconds */
waitCount--;
if (!ret &&
(sc->aac_support_opt2 & AAC_SUPPORTED_DOORBELL_RESET)) {
AAC_MEM0_SETREG4(sc, AAC_SRC_IDBR, reset_mask);
/*
* We need to wait for 5 seconds before accessing the
* doorbell again;
* 10000 * 100us = 1000,000us = 1000ms = 1s
*/
waitCount = 5 * 10000;
while (waitCount) {
DELAY(100); /* delay 100 microseconds */
waitCount--;
}
}
}

View File

@ -1017,8 +1017,8 @@ aac_cam_action(struct cam_sim *sim, union ccb *ccb)
cpi->version_num = 1;
cpi->target_sprt = 0;
cpi->hba_eng_cnt = 0;
cpi->max_target = camsc->inf->TargetsPerBus;
cpi->max_lun = 8; /* Per the controller spec */
cpi->max_target = camsc->inf->TargetsPerBus - 1;
cpi->max_lun = 7; /* Per the controller spec */
cpi->initiator_id = camsc->inf->InitiatorBusId;
cpi->bus_id = camsc->inf->BusNumber;
#if __FreeBSD_version >= 800000
@ -1389,15 +1389,9 @@ aacraid_startio(struct aac_softc *sc)
* Try to get a command that's been put off for lack of
* resources
*/
if (sc->flags & AAC_FLAGS_SYNC_MODE) {
/* sync. transfer mode */
if (sc->aac_sync_cm)
break;
cm = aac_dequeue_ready(sc);
sc->aac_sync_cm = cm;
} else {
cm = aac_dequeue_ready(sc);
}
if ((sc->flags & AAC_FLAGS_SYNC_MODE) && sc->aac_sync_cm)
break;
cm = aac_dequeue_ready(sc);
/* nothing to do? */
if (cm == NULL)

View File

@ -42,7 +42,7 @@
/*
* Misc. magic numbers.
*/
#define AAC_MAX_CONTAINERS 64
#define AAC_MAX_CONTAINERS 240
#define AAC_BLOCK_SIZE 512
/*

View File

@ -49,7 +49,7 @@
#define AAC_DRIVER_MAJOR_VERSION 3
#define AAC_DRIVER_MINOR_VERSION 2
#define AAC_DRIVER_BUGFIX_LEVEL 5
#define AAC_DRIVER_BUGFIX_LEVEL 10
#define AAC_DRIVER_TYPE AAC_TYPE_RELEASE
#ifndef AAC_DRIVER_BUILD
@ -481,9 +481,12 @@ struct aac_softc
u_int32_t aac_feature_bits; /* feature bits from suppl. info */
u_int32_t aac_support_opt2; /* supp. options from suppl. info */
u_int32_t aac_max_aif; /* max. AIF count */
u_int32_t doorbell_mask; /* for IOP reset */
u_int32_t aac_max_msix; /* max. MSI-X vectors */
u_int32_t aac_vector_cap; /* MSI-X vector capab.*/
int msi_enabled; /* MSI/MSI-X enabled */
int msi_tupelo; /* Series 6 support for */
/* single MSI interrupt */
#define AAC_CAM_TARGET_WILDCARD ~0
void (*cam_rescan_cb)(struct aac_softc *, uint32_t,
uint32_t);