summaryrefslogtreecommitdiffstats
path: root/sys/boot/ofw
diff options
context:
space:
mode:
authormarius <marius@FreeBSD.org>2005-10-25 12:51:49 +0000
committermarius <marius@FreeBSD.org>2005-10-25 12:51:49 +0000
commitda8bcd86a3e9a84347d573fb5b4b12d5adaab077 (patch)
tree91ac6bf9691cc8539336a6f9e98ba0eb23cb3d04 /sys/boot/ofw
parente5242bfb17c17c2a2d04b54f18885f14888d590e (diff)
downloadFreeBSD-src-da8bcd86a3e9a84347d573fb5b4b12d5adaab077.zip
FreeBSD-src-da8bcd86a3e9a84347d573fb5b4b12d5adaab077.tar.gz
- Add a workaround for the fact that OFW doesn't guarantee that
devices can be opened multiple times simultaneously but we're expected to be able to do so by the rest of the loader. This fixes booting from disks attached to the on-board SCSI controller of Sun Ultra 1 (previously this triggered a trap) and probably also of AX1115 boards. - While here, remove unused variables and add empty lines where style(9) requires such. Tested on: powerpc (grehan), sparc64 MFC after: 1 month
Diffstat (limited to 'sys/boot/ofw')
-rw-r--r--sys/boot/ofw/libofw/ofw_disk.c65
1 files changed, 58 insertions, 7 deletions
diff --git a/sys/boot/ofw/libofw/ofw_disk.c b/sys/boot/ofw/libofw/ofw_disk.c
index dfeafe0..e859c8f 100644
--- a/sys/boot/ofw/libofw/ofw_disk.c
+++ b/sys/boot/ofw/libofw/ofw_disk.c
@@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$");
*/
#include <sys/param.h>
+#include <sys/queue.h>
#include <netinet/in.h>
@@ -60,9 +61,18 @@ struct devsw ofwdisk = {
ofwd_print
};
+struct opened_dev {
+ ihandle_t handle;
+ u_int count;
+ SLIST_ENTRY(opened_dev) link;
+};
+
+SLIST_HEAD(, opened_dev) opened_devs = SLIST_HEAD_INITIALIZER(opened_dev);
+
static int
ofwd_init(void)
{
+
return 0;
}
@@ -73,7 +83,6 @@ ofwd_strategy(void *devdata, int flag, daddr_t dblk, size_t size, char *buf,
struct ofw_devdesc *dp = (struct ofw_devdesc *)devdata;
daddr_t pos;
int n;
- int i, j;
pos = dblk * 512;
do {
@@ -90,18 +99,47 @@ ofwd_strategy(void *devdata, int flag, daddr_t dblk, size_t size, char *buf,
static int
ofwd_open(struct open_file *f, ...)
{
+ char path[256];
struct ofw_devdesc *dp;
- phandle_t handle;
+ struct opened_dev *odp;
va_list vl;
va_start(vl, f);
dp = va_arg(vl, struct ofw_devdesc *);
va_end(vl);
- if ((handle = OF_open(dp->d_path)) == -1) {
+ /*
+ * We're not guaranteed to be able to open a device more than once
+ * simultaneously and there is no OFW standard method to determine
+ * whether a device is already opened. Opening a device more than
+ * once happens to work with most OFW block device drivers but
+ * triggers a trap with at least the driver for the on-board SCSI
+ * controller in Sun Ultra 1. Upper layers and MI code expect to
+ * be able to open a device more than once however. As a workaround
+ * keep track of the opened devices and reuse the instance handle
+ * when asked to open an already opened device.
+ */
+ SLIST_FOREACH(odp, &opened_devs, link) {
+ if (OF_instance_to_path(odp->handle, path, sizeof(path)) == -1)
+ continue;
+ if (strcmp(path, dp->d_path) == 0) {
+ odp->count++;
+ dp->d_handle = odp->handle;
+ return 0;
+ }
+ }
+ odp = malloc(sizeof(struct opened_dev));
+ if (odp == NULL) {
+ printf("ofwd_open: malloc failed\n");
+ return ENOMEM;
+ }
+ if ((odp->handle = OF_open(dp->d_path)) == -1) {
printf("ofwd_open: Could not open %s\n", dp->d_path);
- return 1;
+ free(odp);
+ return ENOENT;
}
- dp->d_handle = handle;
+ odp->count = 1;
+ SLIST_INSERT_HEAD(&opened_devs, odp, link);
+ dp->d_handle = odp->handle;
return 0;
}
@@ -109,8 +147,20 @@ static int
ofwd_close(struct open_file *f)
{
struct ofw_devdesc *dev = f->f_devdata;
-
- OF_close(dev->d_handle);
+ struct opened_dev *odp;
+
+ SLIST_FOREACH(odp, &opened_devs, link) {
+ if (odp->handle == dev->d_handle) {
+ odp->count--;
+ if (odp->count == 0) {
+ SLIST_REMOVE(&opened_devs, odp, opened_dev,
+ link);
+ OF_close(odp->handle);
+ free(odp);
+ }
+ break;
+ }
+ }
return 0;
}
@@ -124,4 +174,5 @@ ofwd_ioctl(struct open_file *f, u_long cmd, void *data)
static void
ofwd_print(int verbose)
{
+
}
OpenPOWER on IntegriCloud