mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-20 11:11:24 +00:00
Several fixes to allow firmware/BIOS flash access from user-level:
- remove special handling of zero length transfers in mpi_pre_fw_upload(); - add missing MPS_CM_FLAGS_DATAIN flag in mpi_pre_fw_upload(); - move mps_user_setup_request() call into proper place; - increase user command timeout from 30 to 60 seconds; - avoid NULL dereference panic in case of firmware crash. Set max DMA segment size to 24bit, as MPI SGE supports it. Use mps_add_dmaseg() to add empty SGE instead of custom code. Tune endianness safety. Reviewed by: Desai, Kashyap <Kashyap.Desai@lsi.com> Sponsored by: iXsystems, Inc.
This commit is contained in:
parent
814124c33e
commit
61c49b4dd1
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=238974
@ -924,7 +924,7 @@ mps_alloc_requests(struct mps_softc *sc)
|
||||
NULL, NULL, /* filter, filterarg */
|
||||
BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
|
||||
nsegs, /* nsegments */
|
||||
BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
|
||||
BUS_SPACE_MAXSIZE_24BIT,/* maxsegsize */
|
||||
BUS_DMA_ALLOCNOW, /* flags */
|
||||
busdma_lock_mutex, /* lockfunc */
|
||||
&sc->mps_mtx, /* lockarg */
|
||||
@ -2014,7 +2014,6 @@ mps_push_sge(struct mps_command *cm, void *sgep, size_t len, int segsleft)
|
||||
MPI2_SGE_SIMPLE64 *sge = sgep;
|
||||
int error, type;
|
||||
uint32_t saved_buf_len, saved_address_low, saved_address_high;
|
||||
u32 sge_flags;
|
||||
|
||||
type = (tc->Flags & MPI2_SGE_FLAGS_ELEMENT_MASK);
|
||||
|
||||
@ -2034,14 +2033,12 @@ mps_push_sge(struct mps_command *cm, void *sgep, size_t len, int segsleft)
|
||||
break;
|
||||
case MPI2_SGE_FLAGS_SIMPLE_ELEMENT:
|
||||
/* Driver only uses 64-bit SGE simple elements */
|
||||
sge = sgep;
|
||||
if (len != MPS_SGE64_SIZE)
|
||||
panic("SGE simple %p length %u or %zu?", sge,
|
||||
MPS_SGE64_SIZE, len);
|
||||
if (((sge->FlagsLength >> MPI2_SGE_FLAGS_SHIFT) &
|
||||
if (((le32toh(sge->FlagsLength) >> MPI2_SGE_FLAGS_SHIFT) &
|
||||
MPI2_SGE_FLAGS_ADDRESS_SIZE) == 0)
|
||||
panic("SGE simple %p flags %02x not marked 64-bit?",
|
||||
sge, sge->FlagsLength >> MPI2_SGE_FLAGS_SHIFT);
|
||||
panic("SGE simple %p not marked 64-bit?", sge);
|
||||
|
||||
break;
|
||||
default:
|
||||
@ -2073,8 +2070,8 @@ mps_push_sge(struct mps_command *cm, void *sgep, size_t len, int segsleft)
|
||||
* Mark as last element in this chain if necessary.
|
||||
*/
|
||||
if (type == MPI2_SGE_FLAGS_SIMPLE_ELEMENT) {
|
||||
sge->FlagsLength |=
|
||||
(MPI2_SGE_FLAGS_LAST_ELEMENT << MPI2_SGE_FLAGS_SHIFT);
|
||||
sge->FlagsLength |= htole32(
|
||||
MPI2_SGE_FLAGS_LAST_ELEMENT << MPI2_SGE_FLAGS_SHIFT);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2083,11 +2080,6 @@ mps_push_sge(struct mps_command *cm, void *sgep, size_t len, int segsleft)
|
||||
* understanding the code.
|
||||
*/
|
||||
cm->cm_sglsize -= len;
|
||||
/* Endian Safe code */
|
||||
sge_flags = sge->FlagsLength;
|
||||
sge->FlagsLength = htole32(sge_flags);
|
||||
sge->Address.High = htole32(sge->Address.High);
|
||||
sge->Address.Low = htole32(sge->Address.Low);
|
||||
bcopy(sgep, cm->cm_sge, len);
|
||||
cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge + len);
|
||||
return (mps_add_chain(cm));
|
||||
@ -2127,27 +2119,22 @@ mps_push_sge(struct mps_command *cm, void *sgep, size_t len, int segsleft)
|
||||
* 2 SGL's for a bi-directional request, they both use the same
|
||||
* DMA buffer (same cm command).
|
||||
*/
|
||||
saved_buf_len = sge->FlagsLength & 0x00FFFFFF;
|
||||
saved_buf_len = le32toh(sge->FlagsLength) & 0x00FFFFFF;
|
||||
saved_address_low = sge->Address.Low;
|
||||
saved_address_high = sge->Address.High;
|
||||
if (cm->cm_out_len) {
|
||||
sge->FlagsLength = cm->cm_out_len |
|
||||
sge->FlagsLength = htole32(cm->cm_out_len |
|
||||
((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
|
||||
MPI2_SGE_FLAGS_END_OF_BUFFER |
|
||||
MPI2_SGE_FLAGS_HOST_TO_IOC |
|
||||
MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
|
||||
MPI2_SGE_FLAGS_SHIFT);
|
||||
MPI2_SGE_FLAGS_SHIFT));
|
||||
cm->cm_sglsize -= len;
|
||||
/* Endian Safe code */
|
||||
sge_flags = sge->FlagsLength;
|
||||
sge->FlagsLength = htole32(sge_flags);
|
||||
sge->Address.High = htole32(sge->Address.High);
|
||||
sge->Address.Low = htole32(sge->Address.Low);
|
||||
bcopy(sgep, cm->cm_sge, len);
|
||||
cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge
|
||||
+ len);
|
||||
}
|
||||
sge->FlagsLength = saved_buf_len |
|
||||
saved_buf_len |=
|
||||
((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
|
||||
MPI2_SGE_FLAGS_END_OF_BUFFER |
|
||||
MPI2_SGE_FLAGS_LAST_ELEMENT |
|
||||
@ -2155,24 +2142,20 @@ mps_push_sge(struct mps_command *cm, void *sgep, size_t len, int segsleft)
|
||||
MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
|
||||
MPI2_SGE_FLAGS_SHIFT);
|
||||
if (cm->cm_flags & MPS_CM_FLAGS_DATAIN) {
|
||||
sge->FlagsLength |=
|
||||
saved_buf_len |=
|
||||
((uint32_t)(MPI2_SGE_FLAGS_IOC_TO_HOST) <<
|
||||
MPI2_SGE_FLAGS_SHIFT);
|
||||
} else {
|
||||
sge->FlagsLength |=
|
||||
saved_buf_len |=
|
||||
((uint32_t)(MPI2_SGE_FLAGS_HOST_TO_IOC) <<
|
||||
MPI2_SGE_FLAGS_SHIFT);
|
||||
}
|
||||
sge->FlagsLength = htole32(saved_buf_len);
|
||||
sge->Address.Low = saved_address_low;
|
||||
sge->Address.High = saved_address_high;
|
||||
}
|
||||
|
||||
cm->cm_sglsize -= len;
|
||||
/* Endian Safe code */
|
||||
sge_flags = sge->FlagsLength;
|
||||
sge->FlagsLength = htole32(sge_flags);
|
||||
sge->Address.High = htole32(sge->Address.High);
|
||||
sge->Address.Low = htole32(sge->Address.Low);
|
||||
bcopy(sgep, cm->cm_sge, len);
|
||||
cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge + len);
|
||||
return (0);
|
||||
@ -2190,10 +2173,10 @@ mps_add_dmaseg(struct mps_command *cm, vm_paddr_t pa, size_t len, u_int flags,
|
||||
/*
|
||||
* This driver always uses 64-bit address elements for simplicity.
|
||||
*/
|
||||
bzero(&sge, sizeof(sge));
|
||||
flags |= MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
|
||||
MPI2_SGE_FLAGS_64_BIT_ADDRESSING;
|
||||
/* Set Endian safe macro in mps_push_sge */
|
||||
sge.FlagsLength = len | (flags << MPI2_SGE_FLAGS_SHIFT);
|
||||
sge.FlagsLength = htole32(len | (flags << MPI2_SGE_FLAGS_SHIFT));
|
||||
mps_from_u64(pa, &sge.Address);
|
||||
|
||||
return (mps_push_sge(cm, &sge, sizeof sge, segsleft));
|
||||
@ -2290,7 +2273,6 @@ mps_data_cb2(void *arg, bus_dma_segment_t *segs, int nsegs, bus_size_t mapsize,
|
||||
int
|
||||
mps_map_command(struct mps_softc *sc, struct mps_command *cm)
|
||||
{
|
||||
MPI2_SGE_SIMPLE32 *sge;
|
||||
int error = 0;
|
||||
|
||||
if (cm->cm_flags & MPS_CM_FLAGS_USE_UIO) {
|
||||
@ -2301,15 +2283,8 @@ mps_map_command(struct mps_softc *sc, struct mps_command *cm)
|
||||
cm->cm_data, cm->cm_length, mps_data_cb, cm, 0);
|
||||
} else {
|
||||
/* Add a zero-length element as needed */
|
||||
if (cm->cm_sge != NULL) {
|
||||
sge = (MPI2_SGE_SIMPLE32 *)cm->cm_sge;
|
||||
sge->FlagsLength = htole32((MPI2_SGE_FLAGS_LAST_ELEMENT |
|
||||
MPI2_SGE_FLAGS_END_OF_BUFFER |
|
||||
MPI2_SGE_FLAGS_END_OF_LIST |
|
||||
MPI2_SGE_FLAGS_SIMPLE_ELEMENT) <<
|
||||
MPI2_SGE_FLAGS_SHIFT);
|
||||
sge->Address = 0;
|
||||
}
|
||||
if (cm->cm_sge != NULL)
|
||||
mps_add_dmaseg(cm, 0, 0, 0, 1);
|
||||
mps_enqueue_request(sc, cm);
|
||||
}
|
||||
|
||||
|
@ -463,10 +463,12 @@ mps_print_sgl(struct mps_softc *sc, struct mps_command *cm, int offset)
|
||||
sge = (MPI2_SGE_SIMPLE64 *)&frame[offset * 4];
|
||||
printf("SGL for command %p\n", cm);
|
||||
|
||||
hexdump(frame, 128, NULL, 0);
|
||||
while (frame != NULL) {
|
||||
flags = sge->FlagsLength >> MPI2_SGE_FLAGS_SHIFT;
|
||||
printf("seg%d flags=0x%x len=0x%x addr=0x%jx\n", i, flags,
|
||||
sge->FlagsLength & 0xffffff, mps_to_u64(&sge->Address));
|
||||
flags = le32toh(sge->FlagsLength) >> MPI2_SGE_FLAGS_SHIFT;
|
||||
printf("seg%d flags=0x%02x len=0x%06x addr=0x%016jx\n",
|
||||
i, flags, le32toh(sge->FlagsLength) & 0xffffff,
|
||||
mps_to_u64(&sge->Address));
|
||||
if (flags & (MPI2_SGE_FLAGS_END_OF_LIST |
|
||||
MPI2_SGE_FLAGS_END_OF_BUFFER))
|
||||
break;
|
||||
@ -475,8 +477,8 @@ mps_print_sgl(struct mps_softc *sc, struct mps_command *cm, int offset)
|
||||
if (flags & MPI2_SGE_FLAGS_LAST_ELEMENT) {
|
||||
sgc = (MPI2_SGE_CHAIN32 *)sge;
|
||||
printf("chain flags=0x%x len=0x%x Offset=0x%x "
|
||||
"Address=0x%x\n", sgc->Flags, sgc->Length,
|
||||
sgc->NextChainOffset, sgc->Address);
|
||||
"Address=0x%x\n", sgc->Flags, le16toh(sgc->Length),
|
||||
sgc->NextChainOffset, le32toh(sgc->Address));
|
||||
if (chain == NULL)
|
||||
chain = TAILQ_FIRST(&cm->cm_chain_list);
|
||||
else
|
||||
|
@ -534,11 +534,6 @@ mpi_pre_fw_upload(struct mps_command *cm, struct mps_usr_command *cmd)
|
||||
return (EINVAL);
|
||||
|
||||
mpi_init_sge(cm, req, &req->SGL);
|
||||
if (cmd->len == 0) {
|
||||
/* Perhaps just asking what the size of the fw is? */
|
||||
return (0);
|
||||
}
|
||||
|
||||
bzero(&tc, sizeof tc);
|
||||
|
||||
/*
|
||||
@ -554,6 +549,8 @@ mpi_pre_fw_upload(struct mps_command *cm, struct mps_usr_command *cmd)
|
||||
tc.ImageOffset = 0;
|
||||
tc.ImageSize = cmd->len;
|
||||
|
||||
cm->cm_flags |= MPS_CM_FLAGS_DATAIN;
|
||||
|
||||
return (mps_push_sge(cm, &tc, sizeof tc, 0));
|
||||
}
|
||||
|
||||
@ -692,13 +689,6 @@ mps_user_command(struct mps_softc *sc, struct mps_usr_command *cmd)
|
||||
mps_dprint(sc, MPS_INFO, "mps_user_command: Function %02X "
|
||||
"MsgFlags %02X\n", hdr->Function, hdr->MsgFlags );
|
||||
|
||||
err = mps_user_setup_request(cm, cmd);
|
||||
if (err != 0) {
|
||||
mps_printf(sc, "mps_user_command: unsupported function 0x%X\n",
|
||||
hdr->Function );
|
||||
goto RetFreeUnlocked;
|
||||
}
|
||||
|
||||
if (cmd->len > 0) {
|
||||
buf = malloc(cmd->len, M_MPSUSER, M_WAITOK|M_ZERO);
|
||||
if(!buf) {
|
||||
@ -716,8 +706,15 @@ mps_user_command(struct mps_softc *sc, struct mps_usr_command *cmd)
|
||||
cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE;
|
||||
cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
|
||||
|
||||
err = mps_user_setup_request(cm, cmd);
|
||||
if (err != 0) {
|
||||
mps_printf(sc, "mps_user_command: unsupported function 0x%X\n",
|
||||
hdr->Function );
|
||||
goto RetFreeUnlocked;
|
||||
}
|
||||
|
||||
mps_lock(sc);
|
||||
err = mps_wait_command(sc, cm, 30);
|
||||
err = mps_wait_command(sc, cm, 60);
|
||||
|
||||
if (err) {
|
||||
mps_printf(sc, "%s: invalid request: error %d\n",
|
||||
@ -726,7 +723,10 @@ mps_user_command(struct mps_softc *sc, struct mps_usr_command *cmd)
|
||||
}
|
||||
|
||||
rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply;
|
||||
sz = rpl->MsgLength * 4;
|
||||
if (rpl != NULL)
|
||||
sz = rpl->MsgLength * 4;
|
||||
else
|
||||
sz = 0;
|
||||
|
||||
if (sz > cmd->rpl_len) {
|
||||
mps_printf(sc,
|
||||
|
@ -32,7 +32,7 @@
|
||||
#ifndef _MPSVAR_H
|
||||
#define _MPSVAR_H
|
||||
|
||||
#define MPS_DRIVER_VERSION "14.00.00.01-fbsd"
|
||||
#define MPS_DRIVER_VERSION "14.00.00.02-fbsd"
|
||||
|
||||
#define MPS_DB_MAX_WAIT 2500
|
||||
|
||||
@ -627,15 +627,15 @@ do { \
|
||||
static __inline void
|
||||
mps_from_u64(uint64_t data, U64 *mps)
|
||||
{
|
||||
(mps)->High = (uint32_t)((data) >> 32);
|
||||
(mps)->Low = (uint32_t)((data) & 0xffffffff);
|
||||
(mps)->High = htole32((uint32_t)((data) >> 32));
|
||||
(mps)->Low = htole32((uint32_t)((data) & 0xffffffff));
|
||||
}
|
||||
|
||||
static __inline uint64_t
|
||||
mps_to_u64(U64 *data)
|
||||
{
|
||||
|
||||
return (((uint64_t)data->High << 32) | data->Low);
|
||||
return (((uint64_t)le32toh(data->High) << 32) | le32toh(data->Low));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
|
Loading…
Reference in New Issue
Block a user