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:
Doug Ambrisko 2004-08-16 17:23:09 +00:00
parent fc94eecc8f
commit 05f1103b26
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=133870
2 changed files with 144 additions and 98 deletions

View file

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

View file

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