summaryrefslogtreecommitdiff
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
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
-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
-rw-r--r--sys/dev/ic/wdc.c9
-rw-r--r--sys/dev/ic/wdcvar.h3
5 files changed, 108 insertions, 40 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 *);
diff --git a/sys/dev/ic/wdc.c b/sys/dev/ic/wdc.c
index aa0edda0e7b..19f561ed66e 100644
--- a/sys/dev/ic/wdc.c
+++ b/sys/dev/ic/wdc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: wdc.c,v 1.110 2011/04/05 12:06:09 deraadt Exp $ */
+/* $OpenBSD: wdc.c,v 1.111 2011/04/05 19:57:40 deraadt Exp $ */
/* $NetBSD: wdc.c,v 1.68 1999/06/23 19:00:17 bouyer Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved.
@@ -62,6 +62,7 @@
#include <sys/malloc.h>
#include <sys/syslog.h>
#include <sys/proc.h>
+#include <sys/disk.h>
#include <sys/pool.h>
#include <uvm/uvm_extern.h>
@@ -1887,6 +1888,12 @@ wdc_free_xfer(struct channel_softc *chp, struct wdc_xfer *xfer)
struct wdc_softc *wdc = chp->wdc;
int s;
+ if (xfer->c_flags & C_PRIVATEXFER) {
+ chp->ch_flags &= ~WDCF_ACTIVE;
+ TAILQ_REMOVE(&chp->ch_queue->sc_xfer, xfer, c_xferchain);
+ return;
+ }
+
if (wdc->cap & WDC_CAPABILITY_HWLOCK)
(*wdc->free_hw)(chp);
s = splbio();
diff --git a/sys/dev/ic/wdcvar.h b/sys/dev/ic/wdcvar.h
index cdf9ca9b0cc..d18eb944659 100644
--- a/sys/dev/ic/wdcvar.h
+++ b/sys/dev/ic/wdcvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: wdcvar.h,v 1.46 2010/08/29 18:40:33 deraadt Exp $ */
+/* $OpenBSD: wdcvar.h,v 1.47 2011/04/05 19:57:40 deraadt Exp $ */
/* $NetBSD: wdcvar.h,v 1.17 1999/04/11 20:50:29 bouyer Exp $ */
/*-
@@ -226,6 +226,7 @@ struct wdc_xfer {
#define C_SENSE 0x0080 /* cmd is a internal command */
#define C_MEDIA_ACCESS 0x0100 /* is a media access command */
#define C_POLL_MACHINE 0x0200 /* machine has a poll handler */
+#define C_PRIVATEXFER 0x0400 /* privately managed xfer */
/* Informations about our location */
struct channel_softc *chp;