summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Dempsky <matthew@cvs.openbsd.org>2010-09-21 03:33:33 +0000
committerMatthew Dempsky <matthew@cvs.openbsd.org>2010-09-21 03:33:33 +0000
commit03dfc3a036a08beae0013abc0920b3fbf39919ca (patch)
treebb8dec452d6ea2225bfd3bbd19221a94f60041d6
parentd44af743d055b3904231f690ffe156245c35a902 (diff)
Get rid of physio(9) in wdc(4)'s ioctl(2) handler. Based on similar
changes to the SCSI subsystem ioctl(2) handlers. ok dlg@; ok and tweaks krw@; no objections jsg@
-rw-r--r--sys/dev/ic/wdc.c283
1 files changed, 75 insertions, 208 deletions
diff --git a/sys/dev/ic/wdc.c b/sys/dev/ic/wdc.c
index 01d4d0afa15..6c15722f96a 100644
--- a/sys/dev/ic/wdc.c
+++ b/sys/dev/ic/wdc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: wdc.c,v 1.108 2010/08/29 18:40:33 deraadt Exp $ */
+/* $OpenBSD: wdc.c,v 1.109 2010/09/21 03:33:32 matthew Exp $ */
/* $NetBSD: wdc.c,v 1.68 1999/06/23 19:00:17 bouyer Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved.
@@ -1939,201 +1939,103 @@ wdcbit_bucket(struct channel_softc *chp, int size)
#include <sys/ataio.h>
#include <sys/file.h>
-#include <sys/buf.h>
-
-/*
- * Glue necessary to hook ATAIOCCOMMAND into physio
- */
-
-struct wdc_ioctl {
- LIST_ENTRY(wdc_ioctl) wi_list;
- struct buf wi_bp;
- struct uio wi_uio;
- struct iovec wi_iov;
- atareq_t wi_atareq;
- struct ata_drive_datas *wi_drvp;
-};
-struct wdc_ioctl *wdc_ioctl_find(struct buf *);
-void wdc_ioctl_free(struct wdc_ioctl *);
-struct wdc_ioctl *wdc_ioctl_get(void);
-void wdc_ioctl_strategy(struct buf *);
+int wdc_ioc_ata_cmd(struct ata_drive_datas *, atareq_t *);
-LIST_HEAD(, wdc_ioctl) wi_head;
-
-/*
- * Allocate space for a ioctl queue structure. Mostly taken from
- * scsipi_ioctl.c
- */
-struct wdc_ioctl *
-wdc_ioctl_get(void)
-{
- struct wdc_ioctl *wi;
- int s;
-
- wi = malloc(sizeof(*wi), M_TEMP, M_WAITOK | M_ZERO);
- s = splbio();
- LIST_INSERT_HEAD(&wi_head, wi, wi_list);
- splx(s);
- return (wi);
-}
-
-/*
- * Free an ioctl structure and remove it from our list
- */
-
-void
-wdc_ioctl_free(struct wdc_ioctl *wi)
-{
- int s;
-
- s = splbio();
- LIST_REMOVE(wi, wi_list);
- splx(s);
- free(wi, M_TEMP);
-}
-
-/*
- * Find a wdc_ioctl structure based on the struct buf.
- */
-
-struct wdc_ioctl *
-wdc_ioctl_find(struct buf *bp)
-{
- struct wdc_ioctl *wi;
- int s;
-
- s = splbio();
- LIST_FOREACH(wi, &wi_head, wi_list)
- if (bp == &wi->wi_bp)
- break;
- splx(s);
- return (wi);
-}
-
-/*
- * Ioctl pseudo strategy routine
- *
- * This is mostly stolen from scsipi_ioctl.c:scsistrategy(). What
- * happens here is:
- *
- * - wdioctl() queues a wdc_ioctl structure.
- *
- * - wdioctl() calls physio/wdc_ioctl_strategy based on whether or not
- * user space I/O is required. If physio() is called, physio() eventually
- * calls wdc_ioctl_strategy().
- *
- * - In either case, wdc_ioctl_strategy() calls wdc_exec_command()
- * to perform the actual command
- *
- * The reason for the use of the pseudo strategy routine is because
- * when doing I/O to/from user space, physio _really_ wants to be in
- * the loop. We could put the entire buffer into the ioctl request
- * structure, but that won't scale if we want to do things like download
- * microcode.
- */
-
-void
-wdc_ioctl_strategy(struct buf *bp)
+int
+wdc_ioc_ata_cmd(struct ata_drive_datas *drvp, atareq_t *atareq)
{
- struct wdc_ioctl *wi;
struct wdc_command wdc_c;
- int error = 0;
- int s;
-
- wi = wdc_ioctl_find(bp);
- if (wi == NULL) {
- printf("user_strat: No ioctl\n");
- error = EINVAL;
- goto bad;
- }
-
- bzero(&wdc_c, sizeof(wdc_c));
+ int err = 0;
/*
- * Abort if physio broke up the transfer
+ * Make sure a timeout was supplied in the ioctl request
*/
+ if (atareq->timeout == 0)
+ return (EINVAL);
- if ((u_long)bp->b_bcount != wi->wi_atareq.datalen) {
- printf("physio split wd ioctl request... cannot proceed\n");
- error = EIO;
- goto bad;
- }
+ if (atareq->datalen > MAXPHYS)
+ return (EINVAL);
- /*
- * Make sure a timeout was supplied in the ioctl request
- */
+ bzero(&wdc_c, sizeof(wdc_c));
- if (wi->wi_atareq.timeout == 0) {
- error = EINVAL;
- goto bad;
+ if (atareq->datalen > 0) {
+ /* XXX dma accessible */
+ wdc_c.data = malloc(atareq->datalen, M_TEMP,
+ M_WAITOK | M_CANFAIL | M_ZERO);
+ if (wdc_c.data == NULL) {
+ err = ENOMEM;
+ goto err;
+ }
+ wdc_c.bcount = atareq->datalen;
}
- if (wi->wi_atareq.flags & ATACMD_READ)
+ wdc_c.flags = AT_WAIT;
+ if (atareq->flags & ATACMD_READ)
wdc_c.flags |= AT_READ;
- else if (wi->wi_atareq.flags & ATACMD_WRITE)
+ if (atareq->flags & ATACMD_WRITE) {
+ if (atareq->datalen > 0) {
+ err = copyin(atareq->databuf, wdc_c.data,
+ atareq->datalen);
+ if (err != 0)
+ goto err;
+ }
wdc_c.flags |= AT_WRITE;
-
- if (wi->wi_atareq.flags & ATACMD_READREG)
+ }
+ if (atareq->flags & ATACMD_READREG)
wdc_c.flags |= AT_READREG;
- wdc_c.flags |= AT_WAIT;
-
- wdc_c.timeout = wi->wi_atareq.timeout;
- wdc_c.r_command = wi->wi_atareq.command;
- wdc_c.r_head = wi->wi_atareq.head & 0x0f;
- wdc_c.r_cyl = wi->wi_atareq.cylinder;
- wdc_c.r_sector = wi->wi_atareq.sec_num;
- wdc_c.r_count = wi->wi_atareq.sec_count;
- wdc_c.r_precomp = wi->wi_atareq.features;
- if (wi->wi_drvp->drive_flags & DRIVE_ATAPI) {
- wdc_c.r_st_bmask = 0;
- wdc_c.r_st_pmask = 0;
+ wdc_c.timeout = atareq->timeout;
+ wdc_c.r_command = atareq->command;
+ wdc_c.r_head = atareq->head & 0x0f;
+ wdc_c.r_cyl = atareq->cylinder;
+ wdc_c.r_sector = atareq->sec_num;
+ wdc_c.r_count = atareq->sec_count;
+ wdc_c.r_precomp = atareq->features;
+ if (drvp->drive_flags & DRIVE_ATAPI) {
if (wdc_c.r_command == WDCC_IDENTIFY)
wdc_c.r_command = ATAPI_IDENTIFY_DEVICE;
} else {
wdc_c.r_st_bmask = WDCS_DRDY;
wdc_c.r_st_pmask = WDCS_DRDY;
}
- wdc_c.data = wi->wi_bp.b_data;
- wdc_c.bcount = wi->wi_bp.b_bcount;
- if (wdc_exec_command(wi->wi_drvp, &wdc_c) != WDC_COMPLETE) {
- wi->wi_atareq.retsts = ATACMD_ERROR;
- goto bad;
+ if (wdc_exec_command(drvp, &wdc_c) != WDC_COMPLETE) {
+ atareq->retsts = ATACMD_ERROR;
+ goto copyout;
}
if (wdc_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
if (wdc_c.flags & AT_ERROR) {
- wi->wi_atareq.retsts = ATACMD_ERROR;
- wi->wi_atareq.error = wdc_c.r_error;
+ atareq->retsts = ATACMD_ERROR;
+ atareq->error = wdc_c.r_error;
} else if (wdc_c.flags & AT_DF)
- wi->wi_atareq.retsts = ATACMD_DF;
+ atareq->retsts = ATACMD_DF;
else
- wi->wi_atareq.retsts = ATACMD_TIMEOUT;
+ atareq->retsts = ATACMD_TIMEOUT;
} else {
- wi->wi_atareq.retsts = ATACMD_OK;
- if (wi->wi_atareq.flags & ATACMD_READREG) {
- wi->wi_atareq.head = wdc_c.r_head ;
- wi->wi_atareq.cylinder = wdc_c.r_cyl;
- wi->wi_atareq.sec_num = wdc_c.r_sector;
- wi->wi_atareq.sec_count = wdc_c.r_count;
- wi->wi_atareq.features = wdc_c.r_precomp;
- wi->wi_atareq.error = wdc_c.r_error;
+ atareq->retsts = ATACMD_OK;
+ if (atareq->flags & ATACMD_READREG) {
+ atareq->head = wdc_c.r_head;
+ atareq->cylinder = wdc_c.r_cyl;
+ atareq->sec_num = wdc_c.r_sector;
+ atareq->sec_count = wdc_c.r_count;
+ atareq->features = wdc_c.r_precomp;
+ atareq->error = wdc_c.r_error;
}
}
- bp->b_error = 0;
- s = splbio();
- biodone(bp);
- splx(s);
- return;
-bad:
- bp->b_flags |= B_ERROR;
- bp->b_error = error;
- s = splbio();
- biodone(bp);
- splx(s);
+copyout:
+ if (atareq->datalen > 0 && atareq->flags & ATACMD_READ) {
+ err = copyout(wdc_c.data, atareq->databuf, atareq->datalen);
+ if (err != 0)
+ goto err;
+ }
+
+err:
+ if (wdc_c.data)
+ free(wdc_c.data, M_TEMP);
+ return (err);
}
int
@@ -2166,54 +2068,19 @@ wdc_ioctl(struct ata_drive_datas *drvp, u_long xfer, caddr_t addr, int flag,
}
#endif /* WDCDEBUG */
- case ATAIOCCOMMAND:
+ case ATAIOCCOMMAND: {
+ atareq_t *atareq = (atareq_t *)addr;
+
/*
* Make sure this command is (relatively) safe first
*/
- if ((((atareq_t *) addr)->flags & ATACMD_READ) == 0 &&
- (flag & FWRITE) == 0) {
- error = EBADF;
- goto exit;
- }
- {
- struct wdc_ioctl *wi;
- atareq_t *atareq = (atareq_t *) addr;
-
- wi = wdc_ioctl_get();
- wi->wi_drvp = drvp;
- wi->wi_atareq = *atareq;
-
- if (atareq->datalen && atareq->flags &
- (ATACMD_READ | ATACMD_WRITE)) {
- wi->wi_iov.iov_base = atareq->databuf;
- wi->wi_iov.iov_len = atareq->datalen;
- wi->wi_uio.uio_iov = &wi->wi_iov;
- wi->wi_uio.uio_iovcnt = 1;
- wi->wi_uio.uio_resid = atareq->datalen;
- wi->wi_uio.uio_offset = 0;
- wi->wi_uio.uio_segflg = UIO_USERSPACE;
- wi->wi_uio.uio_rw =
- (atareq->flags & ATACMD_READ) ? B_READ : B_WRITE;
- wi->wi_uio.uio_procp = curproc;
- error = physio(wdc_ioctl_strategy, &wi->wi_bp, 0,
- (atareq->flags & ATACMD_READ) ? B_READ : B_WRITE,
- minphys, &wi->wi_uio);
- } else {
- /* No need to call physio if we don't have any
- user data */
- wi->wi_bp.b_flags = 0;
- wi->wi_bp.b_data = 0;
- wi->wi_bp.b_bcount = 0;
- wi->wi_bp.b_dev = 0;
- wi->wi_bp.b_proc = curproc;
- LIST_INIT(&wi->wi_bp.b_dep);
- wdc_ioctl_strategy(&wi->wi_bp);
- error = wi->wi_bp.b_error;
- }
- *atareq = wi->wi_atareq;
- wdc_ioctl_free(wi);
- goto exit;
- }
+ if ((flag & FWRITE) == 0 && atareq->flags & ATACMD_WRITE)
+ error = EPERM;
+ else
+ error = wdc_ioc_ata_cmd(drvp, atareq);
+ break;
+ }
+
default:
error = ENOTTY;
goto exit;