mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-17 22:04:40 +00:00
Allow i386 binaries to do amr ioctls such as LSI's megamgr on amd64 and
ia64. PR: 63155 Submitted by: Mikhail Teterin Tested on: i386, amd64 (via 64bit Xeon system)
This commit is contained in:
parent
fc94eecc8f
commit
05f1103b26
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=133870
|
@ -398,65 +398,104 @@ static int
|
||||||
amr_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, d_thread_t *td)
|
amr_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, d_thread_t *td)
|
||||||
{
|
{
|
||||||
struct amr_softc *sc = (struct amr_softc *)dev->si_drv1;
|
struct amr_softc *sc = (struct amr_softc *)dev->si_drv1;
|
||||||
int *arg = (int *)addr;
|
union {
|
||||||
struct amr_user_ioctl *au = (struct amr_user_ioctl *)addr;
|
void *_p;
|
||||||
|
struct amr_user_ioctl *au;
|
||||||
|
#ifdef AMR_IO_COMMAND32
|
||||||
|
struct amr_user_ioctl32 *au32;
|
||||||
|
#endif
|
||||||
|
int *result;
|
||||||
|
} arg;
|
||||||
struct amr_command *ac;
|
struct amr_command *ac;
|
||||||
struct amr_mailbox_ioctl *mbi;
|
struct amr_mailbox_ioctl *mbi;
|
||||||
struct amr_passthrough *ap;
|
struct amr_passthrough *ap;
|
||||||
void *dp;
|
void *dp, *au_buffer;
|
||||||
|
unsigned long au_length;
|
||||||
|
unsigned char *au_cmd;
|
||||||
|
int *au_statusp, au_direction;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
debug_called(1);
|
debug_called(1);
|
||||||
|
|
||||||
|
arg._p = (void *)addr;
|
||||||
|
|
||||||
|
switch(cmd) {
|
||||||
|
|
||||||
|
case AMR_IO_VERSION:
|
||||||
|
debug(1, "AMR_IO_VERSION");
|
||||||
|
*arg.result = AMR_IO_VERSION_NUMBER;
|
||||||
|
return(0);
|
||||||
|
|
||||||
|
#ifdef AMR_IO_COMMAND32
|
||||||
|
/*
|
||||||
|
* Accept ioctl-s from 32-bit binaries on non-32-bit
|
||||||
|
* platforms, such as AMD. LSI's MEGAMGR utility is
|
||||||
|
* the only example known today... -mi
|
||||||
|
*/
|
||||||
|
case AMR_IO_COMMAND32:
|
||||||
|
debug(1, "AMR_IO_COMMAND32 0x%x", arg.au32->au_cmd[0]);
|
||||||
|
au_cmd = arg.au32->au_cmd;
|
||||||
|
au_buffer = (void *)(u_int64_t)arg.au32->au_buffer;
|
||||||
|
au_length = arg.au32->au_length;
|
||||||
|
au_direction = arg.au32->au_direction;
|
||||||
|
au_statusp = &arg.au32->au_status;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
case AMR_IO_COMMAND:
|
||||||
|
debug(1, "AMR_IO_COMMAND 0x%x", arg.au->au_cmd[0]);
|
||||||
|
au_cmd = arg.au->au_cmd;
|
||||||
|
au_buffer = (void *)arg.au->au_buffer;
|
||||||
|
au_length = arg.au->au_length;
|
||||||
|
au_direction = arg.au->au_direction;
|
||||||
|
au_statusp = &arg.au->au_status;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
debug(1, "unknown ioctl 0x%lx", cmd);
|
||||||
|
return(ENOIOCTL);
|
||||||
|
}
|
||||||
|
|
||||||
error = 0;
|
error = 0;
|
||||||
dp = NULL;
|
dp = NULL;
|
||||||
ap = NULL;
|
ap = NULL;
|
||||||
ac = NULL;
|
ac = NULL;
|
||||||
switch(cmd) {
|
|
||||||
|
|
||||||
case AMR_IO_VERSION:
|
|
||||||
debug(1, "AMR_IO_VERSION");
|
|
||||||
*arg = AMR_IO_VERSION_NUMBER;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AMR_IO_COMMAND:
|
|
||||||
debug(1, "AMR_IO_COMMAND 0x%x", au->au_cmd[0]);
|
|
||||||
/* handle inbound data buffer */
|
/* handle inbound data buffer */
|
||||||
if (au->au_length != 0) {
|
if (au_length != 0) {
|
||||||
if ((dp = malloc(au->au_length, M_DEVBUF, M_WAITOK)) == NULL) {
|
if ((dp = malloc(au_length, M_DEVBUF, M_WAITOK)) == NULL)
|
||||||
error = ENOMEM;
|
return(ENOMEM);
|
||||||
break;
|
|
||||||
}
|
if ((error = copyin(au_buffer, dp, au_length)) != 0)
|
||||||
if ((error = copyin(au->au_buffer, dp, au->au_length)) != 0)
|
goto out;
|
||||||
break;
|
debug(2, "copyin %ld bytes from %p -> %p", au_length, au_buffer, dp);
|
||||||
debug(2, "copyin %ld bytes from %p -> %p", au->au_length, au->au_buffer, dp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ac = amr_alloccmd(sc)) == NULL) {
|
if ((ac = amr_alloccmd(sc)) == NULL) {
|
||||||
error = ENOMEM;
|
error = ENOMEM;
|
||||||
break;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* handle SCSI passthrough command */
|
/* handle SCSI passthrough command */
|
||||||
if (au->au_cmd[0] == AMR_CMD_PASS) {
|
if (au_cmd[0] == AMR_CMD_PASS) {
|
||||||
if ((ap = malloc(sizeof(*ap), M_DEVBUF, M_WAITOK | M_ZERO)) == NULL) {
|
if ((ap = malloc(sizeof(*ap), M_DEVBUF, M_WAITOK | M_ZERO)) == NULL) {
|
||||||
error = ENOMEM;
|
error = ENOMEM;
|
||||||
break;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copy cdb */
|
/* copy cdb */
|
||||||
ap->ap_cdb_length = au->au_cmd[2];
|
ap->ap_cdb_length = au_cmd[2];
|
||||||
bcopy(&au->au_cmd[3], &ap->ap_cdb[0], ap->ap_cdb_length);
|
bcopy(au_cmd + 3, ap->ap_cdb, ap->ap_cdb_length);
|
||||||
|
|
||||||
/* build passthrough */
|
/* build passthrough */
|
||||||
ap->ap_timeout = au->au_cmd[ap->ap_cdb_length + 3] & 0x07;
|
ap->ap_timeout = au_cmd[ap->ap_cdb_length + 3] & 0x07;
|
||||||
ap->ap_ars = (au->au_cmd[ap->ap_cdb_length + 3] & 0x08) ? 1 : 0;
|
ap->ap_ars = (au_cmd[ap->ap_cdb_length + 3] & 0x08) ? 1 : 0;
|
||||||
ap->ap_islogical = (au->au_cmd[ap->ap_cdb_length + 3] & 0x80) ? 1 : 0;
|
ap->ap_islogical = (au_cmd[ap->ap_cdb_length + 3] & 0x80) ? 1 : 0;
|
||||||
ap->ap_logical_drive_no = au->au_cmd[ap->ap_cdb_length + 4];
|
ap->ap_logical_drive_no = au_cmd[ap->ap_cdb_length + 4];
|
||||||
ap->ap_channel = au->au_cmd[ap->ap_cdb_length + 5];
|
ap->ap_channel = au_cmd[ap->ap_cdb_length + 5];
|
||||||
ap->ap_scsi_id = au->au_cmd[ap->ap_cdb_length + 6];
|
ap->ap_scsi_id = au_cmd[ap->ap_cdb_length + 6];
|
||||||
ap->ap_request_sense_length = 14;
|
ap->ap_request_sense_length = 14;
|
||||||
ap->ap_data_transfer_length = au->au_length;
|
ap->ap_data_transfer_length = au_length;
|
||||||
/* XXX what about the request-sense area? does the caller want it? */
|
/* XXX what about the request-sense area? does the caller want it? */
|
||||||
|
|
||||||
/* build command */
|
/* build command */
|
||||||
|
@ -464,10 +503,10 @@ amr_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, d_thread_t *
|
||||||
ac->ac_length = sizeof(*ap);
|
ac->ac_length = sizeof(*ap);
|
||||||
ac->ac_flags |= AMR_CMD_DATAOUT;
|
ac->ac_flags |= AMR_CMD_DATAOUT;
|
||||||
ac->ac_ccb_data = dp;
|
ac->ac_ccb_data = dp;
|
||||||
ac->ac_ccb_length = au->au_length;
|
ac->ac_ccb_length = au_length;
|
||||||
if (au->au_direction & AMR_IO_READ)
|
if (au_direction & AMR_IO_READ)
|
||||||
ac->ac_flags |= AMR_CMD_CCB_DATAIN;
|
ac->ac_flags |= AMR_CMD_CCB_DATAIN;
|
||||||
if (au->au_direction & AMR_IO_WRITE)
|
if (au_direction & AMR_IO_WRITE)
|
||||||
ac->ac_flags |= AMR_CMD_CCB_DATAOUT;
|
ac->ac_flags |= AMR_CMD_CCB_DATAOUT;
|
||||||
|
|
||||||
ac->ac_mailbox.mb_command = AMR_CMD_PASS;
|
ac->ac_mailbox.mb_command = AMR_CMD_PASS;
|
||||||
|
@ -477,40 +516,34 @@ amr_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, d_thread_t *
|
||||||
mbi = (struct amr_mailbox_ioctl *)&ac->ac_mailbox;
|
mbi = (struct amr_mailbox_ioctl *)&ac->ac_mailbox;
|
||||||
|
|
||||||
/* copy pertinent mailbox items */
|
/* copy pertinent mailbox items */
|
||||||
mbi->mb_command = au->au_cmd[0];
|
mbi->mb_command = au_cmd[0];
|
||||||
mbi->mb_channel = au->au_cmd[1];
|
mbi->mb_channel = au_cmd[1];
|
||||||
mbi->mb_param = au->au_cmd[2];
|
mbi->mb_param = au_cmd[2];
|
||||||
mbi->mb_pad[0] = au->au_cmd[3];
|
mbi->mb_pad[0] = au_cmd[3];
|
||||||
mbi->mb_drive = au->au_cmd[4];
|
mbi->mb_drive = au_cmd[4];
|
||||||
|
|
||||||
/* build the command */
|
/* build the command */
|
||||||
ac->ac_data = dp;
|
ac->ac_data = dp;
|
||||||
ac->ac_length = au->au_length;
|
ac->ac_length = au_length;
|
||||||
if (au->au_direction & AMR_IO_READ)
|
if (au_direction & AMR_IO_READ)
|
||||||
ac->ac_flags |= AMR_CMD_DATAIN;
|
ac->ac_flags |= AMR_CMD_DATAIN;
|
||||||
if (au->au_direction & AMR_IO_WRITE)
|
if (au_direction & AMR_IO_WRITE)
|
||||||
ac->ac_flags |= AMR_CMD_DATAOUT;
|
ac->ac_flags |= AMR_CMD_DATAOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* run the command */
|
/* run the command */
|
||||||
if ((error = amr_wait_command(ac)) != 0)
|
if ((error = amr_wait_command(ac)) != 0)
|
||||||
break;
|
goto out;
|
||||||
|
|
||||||
/* copy out data and set status */
|
/* copy out data and set status */
|
||||||
if (au->au_length != 0)
|
if (au_length != 0)
|
||||||
error = copyout(dp, au->au_buffer, au->au_length);
|
error = copyout(dp, au_buffer, au_length);
|
||||||
debug(2, "copyout %ld bytes from %p -> %p", au->au_length, dp, au->au_buffer);
|
debug(2, "copyout %ld bytes from %p -> %p", au_length, dp, au_buffer);
|
||||||
if (dp != NULL)
|
if (dp != NULL)
|
||||||
debug(2, "%16d", (int)dp);
|
debug(2, "%16d", (int)dp);
|
||||||
au->au_status = ac->ac_status;
|
*au_statusp = ac->ac_status;
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
debug(1, "unknown ioctl 0x%lx", cmd);
|
|
||||||
error = ENOIOCTL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
out:
|
||||||
if (dp != NULL)
|
if (dp != NULL)
|
||||||
free(dp, M_DEVBUF);
|
free(dp, M_DEVBUF);
|
||||||
if (ap != NULL)
|
if (ap != NULL)
|
||||||
|
|
|
@ -60,6 +60,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/ioccom.h>
|
#include <sys/ioccom.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fetch the driver's interface version.
|
* Fetch the driver's interface version.
|
||||||
|
@ -107,3 +108,15 @@ struct amr_user_ioctl {
|
||||||
|
|
||||||
#define AMR_IO_COMMAND _IOWR('A', 0x201, struct amr_user_ioctl)
|
#define AMR_IO_COMMAND _IOWR('A', 0x201, struct amr_user_ioctl)
|
||||||
|
|
||||||
|
#if defined(__amd64__) || defined(__ia64__)
|
||||||
|
|
||||||
|
struct amr_user_ioctl32 {
|
||||||
|
unsigned char au_cmd[32]; /* command text from userspace */
|
||||||
|
u_int32_t au_buffer; /* 32-bit pointer to uspace buf */
|
||||||
|
u_int32_t au_length; /* length of the uspace buffer */
|
||||||
|
int32_t au_direction; /* data transfer direction */
|
||||||
|
int32_t au_status; /* command status returned by adapter */
|
||||||
|
};
|
||||||
|
|
||||||
|
# define AMR_IO_COMMAND32 _IOWR('A', 0x201, struct amr_user_ioctl32)
|
||||||
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue