1
0
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:
Alexander Motin 2012-08-01 17:31:31 +00:00
parent 814124c33e
commit 61c49b4dd1
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=238974
4 changed files with 41 additions and 64 deletions

View File

@ -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);
}

View File

@ -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

View File

@ -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,

View File

@ -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