summaryrefslogtreecommitdiff
path: root/sys/dev/ata
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2011-04-05 19:57:41 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2011-04-05 19:57:41 +0000
commited18855ffcbab0b10b85a6daa0590ee709ecbffb (patch)
tree3331a40ce99cff0d44cdb0068d72fda0409f52be /sys/dev/ata
parentb8b4ecf359b69b2f384dabb79edbf67040b9cf73 (diff)
wd_hibernate_io() is a standalone disk io writer which tries to not
damage kernel memory very much while doing the job. It is not very pretty yet, but improving it will need some MI work. ok mlarkin jsg dlg
Diffstat (limited to 'sys/dev/ata')
-rw-r--r--sys/dev/ata/ata_wdc.c61
-rw-r--r--sys/dev/ata/wd.c36
-rw-r--r--sys/dev/ata/wdvar.h39
3 files changed, 98 insertions, 38 deletions
diff --git a/sys/dev/ata/ata_wdc.c b/sys/dev/ata/ata_wdc.c
index 5b6b7acf731..3840f43ed39 100644
--- a/sys/dev/ata/ata_wdc.c
+++ b/sys/dev/ata/ata_wdc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ata_wdc.c,v 1.36 2011/04/03 23:17:13 dlg Exp $ */
+/* $OpenBSD: ata_wdc.c,v 1.37 2011/04/05 19:57:40 deraadt Exp $ */
/* $NetBSD: ata_wdc.c,v 1.21 1999/08/09 09:43:11 bouyer Exp $ */
/*
@@ -64,6 +64,7 @@
#include <sys/malloc.h>
#include <sys/device.h>
#include <sys/disklabel.h>
+#include <sys/disk.h>
#include <sys/syslog.h>
#include <sys/proc.h>
@@ -112,6 +113,61 @@ int wdc_ata_err(struct ata_drive_datas *, struct ata_bio *);
#define WDC_ATA_RECOV 0x01 /* There was a recovered error */
#define WDC_ATA_ERR 0x02 /* Drive reports an error */
+int
+wd_hibernate_io(dev_t dev, daddr_t blkno, caddr_t addr, size_t size, int wr, void *page)
+{
+ struct {
+ struct wd_softc wd;
+ struct wdc_xfer xfer;
+ struct channel_softc chp;
+ } *my = page;
+ struct wd_softc *real_wd, *wd = &my->wd;
+ struct wdc_xfer *xfer = &my->xfer;
+ struct channel_softc *chp = &my->chp;
+ struct ata_bio *ata_bio;
+ extern struct cfdriver wd_cd;
+
+ real_wd = (struct wd_softc *)disk_lookup(&wd_cd, DISKUNIT(dev));
+ if (real_wd == NULL)
+ return (ENODEV);
+
+ /*
+ * Craft a fake set of softc and related structures
+ * which we think the driver modifies. Some of these will
+ * have pointers which reach to unsafe places, but..
+ */
+ bcopy(real_wd->drvp->chnl_softc, &my->chp, sizeof my->chp);
+ chp->ch_drive[0].chnl_softc = chp;
+ chp->ch_drive[1].chnl_softc = chp;
+
+ bcopy(real_wd, &my->wd, sizeof my->wd);
+ ata_bio = &wd->sc_wdc_bio;
+ ata_bio->wd = wd; /* fixup ata_bio->wd */
+ wd->drvp = &chp->ch_drive[real_wd->drvp->drive];
+
+ /* Fill the request and submit it */
+ wd->sc_wdc_bio.blkno = blkno;
+ wd->sc_wdc_bio.flags = ATA_POLL | ATA_LBA48;
+ if (wr == 0)
+ wd->sc_wdc_bio.flags |= ATA_READ;
+ wd->sc_wdc_bio.bcount = size;
+ wd->sc_wdc_bio.databuf = addr;
+ wd->sc_wdc_bio.wd = wd;
+
+ bzero(&my->xfer, sizeof my->xfer);
+ xfer->c_flags |= C_PRIVATEXFER; /* Our xfer is totally private */
+ xfer->c_flags |= C_POLL;
+ xfer->drive = wd->drvp->drive;
+ xfer->cmd = ata_bio;
+ xfer->databuf = ata_bio->databuf;
+ xfer->c_bcount = ata_bio->bcount;
+ xfer->c_start = wdc_ata_bio_start;
+ xfer->c_intr = wdc_ata_bio_intr;
+ xfer->c_kill_xfer = wdc_ata_bio_kill_xfer;
+ wdc_exec_xfer(chp, xfer);
+ return (ata_bio->flags & ATA_ITSDONE) ? 0 : 1;
+}
+
/*
* Handle block I/O operation. Return WDC_COMPLETE, WDC_QUEUED, or
* WDC_TRY_AGAIN. Must be called at splbio().
@@ -513,7 +569,8 @@ wdc_ata_bio_done(struct channel_softc *chp, struct wdc_xfer *xfer)
(u_int)xfer->c_flags),
DEBUG_XFERS);
- timeout_del(&chp->ch_timo);
+ if ((xfer->c_flags & C_PRIVATEXFER) == 0)
+ timeout_del(&chp->ch_timo);
/* feed back residual bcount to our caller */
ata_bio->bcount = xfer->c_bcount;
diff --git a/sys/dev/ata/wd.c b/sys/dev/ata/wd.c
index ae526354813..23ba6e1ae2b 100644
--- a/sys/dev/ata/wd.c
+++ b/sys/dev/ata/wd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: wd.c,v 1.97 2010/12/31 22:58:40 kettenis Exp $ */
+/* $OpenBSD: wd.c,v 1.98 2011/04/05 19:57:40 deraadt Exp $ */
/* $NetBSD: wd.c,v 1.193 1999/02/28 17:15:27 explorer Exp $ */
/*
@@ -113,40 +113,6 @@ extern int wdcdebug_wd_mask; /* init'ed in ata_wdc.c */
#define WDCDEBUG_PRINT(args, level)
#endif
-struct wd_softc {
- /* General disk infos */
- struct device sc_dev;
- struct disk sc_dk;
- struct bufq sc_bufq;
-
- /* IDE disk soft states */
- struct ata_bio sc_wdc_bio; /* current transfer */
- struct buf *sc_bp; /* buf being transferred */
- struct ata_drive_datas *drvp; /* Our controller's infos */
- int openings;
- struct ataparams sc_params;/* drive characteristics found */
- int sc_flags;
-#define WDF_LOCKED 0x01
-#define WDF_WANTED 0x02
-#define WDF_WLABEL 0x04 /* label is writable */
-#define WDF_LABELLING 0x08 /* writing label */
-/*
- * XXX Nothing resets this yet, but disk change sensing will when ATA-4 is
- * more fully implemented.
- */
-#define WDF_LOADED 0x10 /* parameters loaded */
-#define WDF_WAIT 0x20 /* waiting for resources */
-#define WDF_LBA 0x40 /* using LBA mode */
-#define WDF_LBA48 0x80 /* using 48-bit LBA mode */
-
- u_int64_t sc_capacity;
- int cyl; /* actual drive parameters */
- int heads;
- int sectors;
- int retries; /* number of xfer retry */
- struct timeout sc_restart_timeout;
- void *sc_sdhook;
-};
#define sc_drive sc_wdc_bio.drive
#define sc_mode sc_wdc_bio.mode
diff --git a/sys/dev/ata/wdvar.h b/sys/dev/ata/wdvar.h
index cf41e5ed19b..c27d47df25a 100644
--- a/sys/dev/ata/wdvar.h
+++ b/sys/dev/ata/wdvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: wdvar.h,v 1.14 2010/07/23 07:47:13 jsg Exp $ */
+/* $OpenBSD: wdvar.h,v 1.15 2011/04/05 19:57:40 deraadt Exp $ */
/* $NetBSD: wdvar.h,v 1.3 1998/11/11 19:38:27 bouyer Exp $ */
/*
@@ -59,6 +59,41 @@ struct ata_bio {
struct wd_softc *wd;
};
+struct wd_softc {
+ /* General disk infos */
+ struct device sc_dev;
+ struct disk sc_dk;
+ struct bufq sc_bufq;
+
+ /* IDE disk soft states */
+ struct ata_bio sc_wdc_bio; /* current transfer */
+ struct buf *sc_bp; /* buf being transferred */
+ struct ata_drive_datas *drvp; /* Our controller's infos */
+ int openings;
+ struct ataparams sc_params;/* drive characteristics found */
+ int sc_flags;
+#define WDF_LOCKED 0x01
+#define WDF_WANTED 0x02
+#define WDF_WLABEL 0x04 /* label is writable */
+#define WDF_LABELLING 0x08 /* writing label */
+/*
+ * XXX Nothing resets this yet, but disk change sensing will when ATA-4 is
+ * more fully implemented.
+ */
+#define WDF_LOADED 0x10 /* parameters loaded */
+#define WDF_WAIT 0x20 /* waiting for resources */
+#define WDF_LBA 0x40 /* using LBA mode */
+#define WDF_LBA48 0x80 /* using 48-bit LBA mode */
+
+ u_int64_t sc_capacity;
+ int cyl; /* actual drive parameters */
+ int heads;
+ int sectors;
+ int retries; /* number of xfer retry */
+ struct timeout sc_restart_timeout;
+ void *sc_sdhook;
+};
+
/* drive states stored in ata_drive_datas */
#define RECAL 0
#define RECAL_WAIT 1
@@ -73,6 +108,8 @@ struct ata_bio {
#define READY 10
int wdc_ata_bio(struct ata_drive_datas*, struct ata_bio*);
+int wd_hibernate_io(dev_t dev, daddr_t blkno, caddr_t addr, size_t size,
+ int wr, void *page);
void wddone(void *);