Checkin a facility for specifying a passthrough FIB from userland.

arcconf tool by Adaptec already seems to use for identifying the
Serial Number of the devices.
Some simple things (like FIB setup and bound checks) are retrieved
from the Adaptec's driver, but this implementation is quite different
because it does use the normal buffer dmat area for loading segments
and not a special one (like the Adaptec's one does).

Sponsored by:	Sandvine Incorporated
Discussed with:	emaste, scottl
Reviewed by:	emaste, scottl
MFC:		2 weeks
This commit is contained in:
attilio 2010-03-14 22:38:18 +00:00
parent 40e45eec2f
commit 500e7d9ffd

View File

@ -3063,7 +3063,147 @@ aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib)
static int
aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg)
{
return (EINVAL);
struct aac_command *cm;
struct aac_event *event;
struct aac_fib *fib;
struct aac_srb *srbcmd, *user_srb;
struct aac_sg_entry *sge;
struct aac_sg_entry64 *sge64;
void *srb_sg_address, *ureply;
uint32_t fibsize, srb_sg_bytecount;
int error, transfer_data;
fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
cm = NULL;
transfer_data = 0;
fibsize = 0;
user_srb = (struct aac_srb *)arg;
mtx_lock(&sc->aac_io_lock);
if (aac_alloc_command(sc, &cm)) {
event = malloc(sizeof(struct aac_event), M_AACBUF,
M_NOWAIT | M_ZERO);
if (event == NULL) {
error = EBUSY;
mtx_unlock(&sc->aac_io_lock);
goto out;
}
event->ev_type = AAC_EVENT_CMFREE;
event->ev_callback = aac_ioctl_event;
event->ev_arg = &cm;
aac_add_event(sc, event);
msleep(cm, &sc->aac_io_lock, 0, "aacraw", 0);
}
mtx_unlock(&sc->aac_io_lock);
cm->cm_data = NULL;
fib = cm->cm_fib;
srbcmd = (struct aac_srb *)fib->data;
error = copyin(&user_srb->data_len, &fibsize, sizeof(uint32_t));
if (error != 0)
goto out;
if (fibsize > (sc->aac_max_fib_size - sizeof(struct aac_fib_header))) {
error = EINVAL;
goto out;
}
error = copyin(user_srb, srbcmd, fibsize);
if (error != 0)
goto out;
srbcmd->function = 0;
srbcmd->retry_limit = 0;
if (srbcmd->sg_map.SgCount > 1) {
error = EINVAL;
goto out;
}
/* Retrieve correct SG entries. */
if (fibsize == (sizeof(struct aac_srb) +
srbcmd->sg_map.SgCount * sizeof(struct aac_sg_entry))) {
sge = srbcmd->sg_map.SgEntry;
sge64 = NULL;
srb_sg_bytecount = sge->SgByteCount;
#ifdef __amd64__
srb_sg_address = (void *)(uint64_t)sge->SgAddress;
#else
srb_sg_address = (void *)sge->SgAddress;
#endif
}
#ifdef __amd64__
else if (fibsize == (sizeof(struct aac_srb) +
srbcmd->sg_map.SgCount * sizeof(struct aac_sg_entry64))) {
sge = NULL;
sge64 = (struct aac_sg_entry64 *)srbcmd->sg_map.SgEntry;
srb_sg_bytecount = sge64->SgByteCount;
srb_sg_address = (void *)sge64->SgAddress;
if (sge64->SgAddress > 0xffffffffull &&
(sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
error = EINVAL;
goto out;
}
}
#endif
else {
error = EINVAL;
goto out;
}
ureply = (char *)arg + fibsize;
srbcmd->data_len = srb_sg_bytecount;
if (srbcmd->sg_map.SgCount == 1)
transfer_data = 1;
cm->cm_sgtable = (struct aac_sg_table *)&srbcmd->sg_map;
if (transfer_data) {
cm->cm_datalen = srb_sg_bytecount;
cm->cm_data = malloc(cm->cm_datalen, M_AACBUF, M_NOWAIT);
if (cm->cm_data == NULL) {
error = ENOMEM;
goto out;
}
if (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN)
cm->cm_flags |= AAC_CMD_DATAIN;
if (srbcmd->flags & AAC_SRB_FLAGS_DATA_OUT) {
cm->cm_flags |= AAC_CMD_DATAOUT;
error = copyin(srb_sg_address, cm->cm_data,
cm->cm_datalen);
if (error != 0)
goto out;
}
}
fib->Header.Size = sizeof(struct aac_fib_header) +
sizeof(struct aac_srb);
fib->Header.XferState =
AAC_FIBSTATE_HOSTOWNED |
AAC_FIBSTATE_INITIALISED |
AAC_FIBSTATE_EMPTY |
AAC_FIBSTATE_FROMHOST |
AAC_FIBSTATE_REXPECTED |
AAC_FIBSTATE_NORM |
AAC_FIBSTATE_ASYNC |
AAC_FIBSTATE_FAST_RESPONSE;
fib->Header.Command = (sc->flags & AAC_FLAGS_SG_64BIT) != 0 ?
ScsiPortCommandU64 : ScsiPortCommand;
mtx_lock(&sc->aac_io_lock);
aac_wait_command(cm);
mtx_unlock(&sc->aac_io_lock);
if (transfer_data && (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN) != 0) {
error = copyout(cm->cm_data, srb_sg_address, cm->cm_datalen);
if (error != 0)
goto out;
}
error = copyout(fib->data, ureply, sizeof(struct aac_srb_response));
out:
if (cm != NULL) {
if (cm->cm_data != NULL)
free(cm->cm_data, M_AACBUF);
mtx_lock(&sc->aac_io_lock);
aac_release_command(cm);
mtx_unlock(&sc->aac_io_lock);
}
return(error);
}
/*