- Add in FreeBSD native ioctl that models the Linux version.
- Add a translation so the Linux ioctl's don't conflict with the FreeBSD definition. - Assume Linux 32bit emulation on amd64. This was tested on i386 and amd64 with the 32bit Linux MegaCli. Eventually we should do a 32bit native FreeBSD translation app.
This commit is contained in:
parent
dfc67ec476
commit
c2be47f25f
@ -1797,6 +1797,14 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
|
||||
{
|
||||
struct mfi_softc *sc;
|
||||
union mfi_statrequest *ms;
|
||||
struct mfi_ioc_packet *ioc;
|
||||
struct mfi_ioc_aen *aen;
|
||||
struct mfi_command *cm = NULL;
|
||||
struct mfi_dcmd_frame *dcmd;
|
||||
uint32_t context;
|
||||
uint32_t *sense_ptr;
|
||||
uint8_t *data = NULL, *temp;
|
||||
int i;
|
||||
int error;
|
||||
|
||||
sc = dev->si_drv1;
|
||||
@ -1818,7 +1826,133 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xc1144d01: /* Firmware Linux ioctl shim */
|
||||
case MFI_CMD:
|
||||
ioc = (struct mfi_ioc_packet *)arg;
|
||||
|
||||
mtx_lock(&sc->mfi_io_lock);
|
||||
if ((cm = mfi_dequeue_free(sc)) == NULL) {
|
||||
mtx_unlock(&sc->mfi_io_lock);
|
||||
return (EBUSY);
|
||||
}
|
||||
mtx_unlock(&sc->mfi_io_lock);
|
||||
|
||||
/*
|
||||
* save off original context since copying from user
|
||||
* will clobber some data
|
||||
*/
|
||||
context = cm->cm_frame->header.context;
|
||||
|
||||
bcopy(ioc->mi_frame.raw, cm->cm_frame,
|
||||
ioc->mi_sgl_off); /* Linux can do 2 frames ? */
|
||||
cm->cm_total_frame_size = ioc->mi_sgl_off;
|
||||
cm->cm_sg =
|
||||
(union mfi_sgl *)&cm->cm_frame->bytes[ioc->mi_sgl_off];
|
||||
cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_DATAOUT
|
||||
| MFI_CMD_POLLED;
|
||||
cm->cm_len = cm->cm_frame->header.data_len;
|
||||
cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
|
||||
M_WAITOK | M_ZERO);
|
||||
|
||||
/* restore header context */
|
||||
cm->cm_frame->header.context = context;
|
||||
/* ioctl's are dcmd types */
|
||||
dcmd = &cm->cm_frame->dcmd;
|
||||
|
||||
temp = data;
|
||||
for (i = 0; i < ioc->mi_sge_count; i++) {
|
||||
error = copyin(ioc->mi_sgl[i].iov_base,
|
||||
temp,
|
||||
ioc->mi_sgl[i].iov_len);
|
||||
if (error != 0) {
|
||||
device_printf(sc->mfi_dev,
|
||||
"Copy in failed");
|
||||
goto out;
|
||||
}
|
||||
temp = &temp[ioc->mi_sgl[i].iov_len];
|
||||
}
|
||||
|
||||
if (ioc->mi_sense_len) {
|
||||
sense_ptr =
|
||||
(void *)&cm->cm_frame->bytes[ioc->mi_sense_off];
|
||||
*sense_ptr = cm->cm_sense_busaddr;
|
||||
}
|
||||
|
||||
mtx_lock(&sc->mfi_io_lock);
|
||||
if ((error = mfi_mapcmd(sc, cm)) != 0) {
|
||||
device_printf(sc->mfi_dev,
|
||||
"Controller info buffer map failed");
|
||||
mtx_unlock(&sc->mfi_io_lock);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((error = mfi_polled_command(sc, cm)) != 0) {
|
||||
device_printf(sc->mfi_dev,
|
||||
"Controller polled failed");
|
||||
mtx_unlock(&sc->mfi_io_lock);
|
||||
goto out;
|
||||
}
|
||||
|
||||
bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
|
||||
BUS_DMASYNC_POSTREAD);
|
||||
bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
|
||||
mtx_unlock(&sc->mfi_io_lock);
|
||||
|
||||
temp = data;
|
||||
for (i = 0; i < ioc->mi_sge_count; i++) {
|
||||
error = copyout(temp,
|
||||
ioc->mi_sgl[i].iov_base,
|
||||
ioc->mi_sgl[i].iov_len);
|
||||
if (error != 0) {
|
||||
device_printf(sc->mfi_dev,
|
||||
"Copy out failed");
|
||||
goto out;
|
||||
}
|
||||
temp = &temp[ioc->mi_sgl[i].iov_len];
|
||||
}
|
||||
|
||||
if (ioc->mi_sense_len) {
|
||||
/* copy out sense */
|
||||
sense_ptr = (void *)
|
||||
&ioc->mi_frame.raw[ioc->mi_sense_off];
|
||||
temp = 0;
|
||||
temp += cm->cm_sense_busaddr;
|
||||
error = copyout(temp, sense_ptr,
|
||||
ioc->mi_sense_len);
|
||||
if (error != 0) {
|
||||
device_printf(sc->mfi_dev,
|
||||
"Copy out failed");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ioc->mi_frame.hdr.cmd_status = cm->cm_frame->header.cmd_status;
|
||||
if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) {
|
||||
switch (dcmd->opcode) {
|
||||
case MFI_DCMD_CFG_CLEAR:
|
||||
case MFI_DCMD_CFG_ADD:
|
||||
/*
|
||||
mfi_ldrescan(sc);
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (data)
|
||||
free(data, M_MFIBUF);
|
||||
if (cm) {
|
||||
mtx_lock(&sc->mfi_io_lock);
|
||||
mfi_release_command(cm);
|
||||
mtx_unlock(&sc->mfi_io_lock);
|
||||
}
|
||||
|
||||
break;
|
||||
case MFI_SET_AEN:
|
||||
aen = (struct mfi_ioc_aen *)arg;
|
||||
error = mfi_aen_register(sc, aen->aen_seq_num,
|
||||
aen->aen_class_locale);
|
||||
|
||||
break;
|
||||
case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */
|
||||
{
|
||||
devclass_t devclass;
|
||||
struct mfi_linux_ioc_packet l_ioc;
|
||||
@ -1839,7 +1973,7 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
|
||||
cmd, arg, flag, td));
|
||||
break;
|
||||
}
|
||||
case 0x400c4d03: /* AEN Linux ioctl shim */
|
||||
case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */
|
||||
{
|
||||
devclass_t devclass;
|
||||
struct mfi_linux_ioc_aen l_aen;
|
||||
@ -1880,13 +2014,14 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_threa
|
||||
uint32_t *sense_ptr;
|
||||
uint32_t context;
|
||||
uint8_t *data = NULL, *temp;
|
||||
void *temp_convert;
|
||||
int i;
|
||||
int error;
|
||||
|
||||
sc = dev->si_drv1;
|
||||
error = 0;
|
||||
switch (cmd) {
|
||||
case 0xc1144d01: /* Firmware Linux ioctl shim */
|
||||
case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */
|
||||
error = copyin(arg, &l_ioc, sizeof(l_ioc));
|
||||
if (error != 0)
|
||||
return (error);
|
||||
@ -1924,7 +2059,9 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_threa
|
||||
|
||||
temp = data;
|
||||
for (i = 0; i < l_ioc.lioc_sge_count; i++) {
|
||||
error = copyin(l_ioc.lioc_sgl[i].iov_base,
|
||||
temp_convert =
|
||||
(void *)(uintptr_t)l_ioc.lioc_sgl[i].iov_base;
|
||||
error = copyin(temp_convert,
|
||||
temp,
|
||||
l_ioc.lioc_sgl[i].iov_len);
|
||||
if (error != 0) {
|
||||
@ -1963,8 +2100,10 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_threa
|
||||
|
||||
temp = data;
|
||||
for (i = 0; i < l_ioc.lioc_sge_count; i++) {
|
||||
temp_convert =
|
||||
(void *)(uintptr_t)l_ioc.lioc_sgl[i].iov_base;
|
||||
error = copyout(temp,
|
||||
l_ioc.lioc_sgl[i].iov_base,
|
||||
temp_convert,
|
||||
l_ioc.lioc_sgl[i].iov_len);
|
||||
if (error != 0) {
|
||||
device_printf(sc->mfi_dev,
|
||||
@ -2017,7 +2156,7 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_threa
|
||||
}
|
||||
|
||||
return (error);
|
||||
case 0x400c4d03: /* AEN Linux ioctl shim */
|
||||
case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */
|
||||
error = copyin(arg, &l_aen, sizeof(l_aen));
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
@ -27,6 +27,13 @@
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#if defined(__amd64__) /* Assume amd64 wants 32 bit Linux */
|
||||
struct iovec32 {
|
||||
u_int32_t iov_base;
|
||||
int iov_len;
|
||||
};
|
||||
#endif
|
||||
|
||||
#define MFIQ_FREE 0
|
||||
#define MFIQ_BIO 1
|
||||
#define MFIQ_READY 2
|
||||
@ -43,6 +50,33 @@ union mfi_statrequest {
|
||||
struct mfi_qstat ms_qstat;
|
||||
};
|
||||
|
||||
#define MAX_IOCTL_SGE 16
|
||||
|
||||
struct mfi_ioc_packet {
|
||||
uint16_t mi_adapter_no;
|
||||
uint16_t mi_pad1;
|
||||
uint32_t mi_sgl_off;
|
||||
uint32_t mi_sge_count;
|
||||
uint32_t mi_sense_off;
|
||||
uint32_t mi_sense_len;
|
||||
union {
|
||||
uint8_t raw[128];
|
||||
struct mfi_frame_header hdr;
|
||||
} mi_frame;
|
||||
|
||||
struct iovec mi_sgl[MAX_IOCTL_SGE];
|
||||
} __packed;
|
||||
|
||||
struct mfi_ioc_aen {
|
||||
uint16_t aen_adapter_no;
|
||||
uint16_t aen_pad1;
|
||||
uint32_t aen_seq_num;
|
||||
uint32_t aen_class_locale;
|
||||
} __packed;
|
||||
|
||||
#define MFI_CMD _IOWR('M', 1, struct mfi_ioc_packet)
|
||||
#define MFI_SET_AEN _IOW('M', 3, struct mfi_ioc_aen)
|
||||
|
||||
#define MAX_LINUX_IOCTL_SGE 16
|
||||
|
||||
struct mfi_linux_ioc_packet {
|
||||
@ -57,7 +91,11 @@ struct mfi_linux_ioc_packet {
|
||||
struct mfi_frame_header hdr;
|
||||
} lioc_frame;
|
||||
|
||||
#if defined(__amd64__) /* Assume amd64 wants 32 bit Linux */
|
||||
struct iovec32 lioc_sgl[MAX_LINUX_IOCTL_SGE];
|
||||
#else
|
||||
struct iovec lioc_sgl[MAX_LINUX_IOCTL_SGE];
|
||||
#endif
|
||||
} __packed;
|
||||
|
||||
#define MFIIO_STATS _IOWR('Q', 101, union mfi_statrequest)
|
||||
@ -68,3 +106,12 @@ struct mfi_linux_ioc_aen {
|
||||
uint32_t laen_seq_num;
|
||||
uint32_t laen_class_locale;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Create a second set so the FreeBSD native ioctl doesn't
|
||||
* conflict in FreeBSD ioctl handler. Translate in mfi_linux.c.
|
||||
*/
|
||||
#define MFI_LINUX_CMD 0xc1144d01
|
||||
#define MFI_LINUX_SET_AEN 0x400c4d03
|
||||
#define MFI_LINUX_CMD_2 0xc1144d02
|
||||
#define MFI_LINUX_SET_AEN_2 0x400c4d04
|
||||
|
@ -45,6 +45,9 @@ __FBSDID("$FreeBSD$");
|
||||
#include <compat/linux/linux_ioctl.h>
|
||||
#include <compat/linux/linux_util.h>
|
||||
|
||||
#include <dev/mfi/mfireg.h>
|
||||
#include <dev/mfi/mfi_ioctl.h>
|
||||
|
||||
/* There are multiple ioctl number ranges that need to be handled */
|
||||
#define MFI_LINUX_IOCTL_MIN 0x4d00
|
||||
#define MFI_LINUX_IOCTL_MAX 0x4d04
|
||||
@ -81,10 +84,20 @@ mfi_linux_ioctl(d_thread_t *p, struct linux_ioctl_args *args)
|
||||
{
|
||||
struct file *fp;
|
||||
int error;
|
||||
u_long cmd = args->cmd;
|
||||
|
||||
switch (cmd) {
|
||||
case MFI_LINUX_CMD:
|
||||
cmd = MFI_LINUX_CMD_2;
|
||||
break;
|
||||
case MFI_LINUX_SET_AEN:
|
||||
cmd = MFI_LINUX_SET_AEN_2;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((error = fget(p, args->fd, &fp)) != 0)
|
||||
return (error);
|
||||
error = fo_ioctl(fp, args->cmd, (caddr_t)args->arg, p->td_ucred, p);
|
||||
error = fo_ioctl(fp, cmd, (caddr_t)args->arg, p->td_ucred, p);
|
||||
fdrop(fp, p);
|
||||
return (error);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user