Bug 165025 - [PATCH] zfsboot support for sparc64
Summary: [PATCH] zfsboot support for sparc64
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: sparc64 (show other bugs)
Version: 9.0-RELEASE
Hardware: Any Any
: Normal Affects Only Me
Assignee: freebsd-sparc64 (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-02-12 09:30 UTC by Gavin Mu
Modified: 2012-06-14 21:03 UTC (History)
0 users

See Also:


Attachments
file.diff (10.47 KB, patch)
2012-02-12 09:30 UTC, Gavin Mu
no flags Details | Diff
zfsboot.v2.diff.txt (16.99 KB, text/plain; charset=US-ASCII)
2012-02-27 14:46 UTC, Gavin Mu
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Gavin Mu 2012-02-12 09:30:13 UTC
This patch enables the ZFS boot from zpool on a single whole disk for sparc64.
Two new programs zfsboot and zfsloader are introduced.
zfsboot is written to address [0x200, 0x2000) just like boot1, and is responsible to read zfsloader (one ELF program like loader) from 3.5MB ZFS Boot Block located at [0x80000, 0x400000).

Known Limitations:
1. only zpool on a whole disk is supported, zfs boot from zpool in VTOC8 partitions may not work.
2. boot from mirror/raidz is not supported due to limited dev environment.

Fix: generic steps:
1. build zfsboot and zfsloader
2. create zpool on your disk
# zpool create tank /dev/<your disk, ie. ada0>
3. export the zpool
# zpool export tank
4. install zfsboot
# dd if=boot1 of=/dev/<your disk, ie. ada0> bs=512 skip=1 oseek=1 conv=notrunc
5. install zfsloader to ZFS Book Block location
# dd if=zfsloader of=/dev/<your disk, ie. ada0> bs=512 oseek=1024 conv=notrunc
6. re-import your zpool to install FreeBSD files


Patch attached with submission follows:
How-To-Repeat: NA.
Comment 1 marius 2012-02-12 13:16:19 UTC
> Known Limitations:
> 1. only zpool on a whole disk is supported, zfs boot from zpool in VTOC8 partitions may not work.

Uhm, are you sure you didn't have (the remnants) of a VTOC label on
the disk? I'd expect the firmware to refuse to boot from a disk not
having one.

> 2. boot from mirror/raidz is not supported due to limited dev environment.

Could you also tackle these remaining bits or at least describe what
it would take to support booting from a zpool in a VTOC label, mirror
and raidz?

> 
> >How-To-Repeat:
> NA.
> >Fix:
> generic steps:
> 1. build zfsboot and zfsloader
> 2. create zpool on your disk
> # zpool create tank /dev/<your disk, ie. ada0>
> 3. export the zpool
> # zpool export tank
> 4. install zfsboot
> # dd if=boot1 of=/dev/<your disk, ie. ada0> bs=512 skip=1 oseek=1 conv=notrunc

Assuming there is a VTOC8 label, this could also be done using `gpart -b`,
no?

> 5. install zfsloader to ZFS Book Block location
> # dd if=zfsloader of=/dev/<your disk, ie. ada0> bs=512 oseek=1024 conv=notrunc

I think to vaguely remember there being a zfs command/way of writing
a loader to that 3.5MB boot block area following the uberblock. Do
you know what it is?

In any case, nice work so far!

Marius
Comment 2 Gavin Mu 2012-02-12 14:59:12 UTC
>> Known Limitations:
>> 1. only zpool on a whole disk is supported, zfs boot from zpool in VTOC8 partitions may not work.
>
> Uhm, are you sure you didn't have (the remnants) of a VTOC label on
> the disk? I'd expect the firmware to refuse to boot from a disk not
> having one.
Sorry, it is my fault not writing this here. A fake VTOC8 label is
still required, and it is not conflict with zpool on the whole disk,
since ZFS reserved the first 8KB block unused. the VTOC8 table and
boot1 (or zfsboot) code can be in this 8KB block. command `zpool
create` will not destroy the VTOC8 table and the boot1 code.
>
>> 2. boot from mirror/raidz is not supported due to limited dev environment.
>
> Could you also tackle these remaining bits or at least describe what
> it would take to support booting from a zpool in a VTOC label, mirror
> and raidz?
I do not have enough hardware to test booting from mirror/raidz disks,
so I focus only on booting from one single disk in this PR.
The default zfs_dev.dv_init() traverse all possible disks and
slices/partitions to find all zpool vdev, I simply changed the
behavior to read from one single disk only then it is easy to know
which zpool should be used to boot (there will be only one). To
support booting from mirror/raidz, all disks/slices must be traversed
and it is needed to decide which zpool to boot.

booting from a zpool in VTOC8 label should be possible for me to do
dev/test, I need a little more VTOC8 knowledge and will try it later.
>
>>
>> >How-To-Repeat:
>> NA.
>> >Fix:
>> generic steps:
>> 1. build zfsboot and zfsloader
>> 2. create zpool on your disk
>> # zpool create tank /dev/<your disk, ie. ada0>
>> 3. export the zpool
>> # zpool export tank
>> 4. install zfsboot
>> # dd if=boot1 of=/dev/<your disk, ie. ada0> bs=512 skip=1 oseek=1 conv=notrunc
>
> Assuming there is a VTOC8 label, this could also be done using `gpart -b`,
> no?
Yes, but I think we should keep the zpool exported, otherwise this
command may fail.
>
>> 5. install zfsloader to ZFS Book Block location
>> # dd if=zfsloader of=/dev/<your disk, ie. ada0> bs=512 oseek=1024 conv=notrunc
>
> I think to vaguely remember there being a zfs command/way of writing
> a loader to that 3.5MB boot block area following the uberblock. Do
> you know what it is?
I am also finding this.:) without such command, it will not be able to
update the zfsboot and zfsloader on the disk (dd will report error
since zpool is being used). Maybe we need some other code changes.

>
> In any case, nice work so far!
>
> Marius
>

Cheers,
Gavin Mu
Comment 3 Gavin Mu 2012-02-27 14:46:22 UTC
Here is the updated patch to support zfs boot fully. Now boot from
mirror/raidz pool are also supported.

zfsboot is the enhancement of boot1. Instead of reading "/boot/loader"
from UFS filesystem, it loads the ELF "zfsloader" program from the
3.5MB Boot Block of zpool in current vtoc8 partition (slice).

zfsloader tries to probe the zpool in current vtoc8 partition and if
it is valid, it records the guid, then search all disks to find all
zpools in the vtoc8 partitions with freebsd-zfs tag. zfsloader uses
devalias "disk<n>" to find the disks, so devalias must be defined for
all your bootable disks by OBP (aka. {ok} mode). then it boots from
the zpool with the same guid.

If you use the whole disk as zpool, you can allocate all disk space
into the first vtoc8 partition (for example, ada0a in FreeBSD) tag
with freebsd-zfs to create zpool. It is same with creating zpool on
the whole disk (ada0).

For reading from multiple disks, some ofw code are changed. The former
code does not work when reading from multiple disks and I am not sure
if it is possible and how to do this. (I googled but did not find more
useful things). So I changed the code to close the current disk before
a new disk is opened, and there will be only one disk opened
simultaneously. I am not sure if this will slow the disk reading for
booting from raidz pool. (It is several minutes slow on my V100
machine to boot from raidz zpool).

Steps to use zfs boot:
1. create vtoc8
# gpart create -s vtoc8 ada0

2. add partitions, for example
# gpart add -t freebsd-swap -s 4g ada0
# gpart add -t freebsd-zfs ada0
the disk will be:
# gpart show
=>       0  78156480  ada0  VTOC8  (37G)
         0   8388480     1  freebsd-swap  (4G)
   8388480   69768000     2  freebsd-zfs  (33G)

3. create zpool
# zpool create tank ada0b
or if you use mirrored/raidz type:
# zpool create tank mirror ada0b ada1b
# zpool create tank raidz ada0b ada1b ada2b....

4. write boot1
# gpart bootcode -p /boot/boot1 -i 1 ada0

5. write zfsloader into ZFS Boot Block, currently there is no dedicate
program to do this, so use dd instead.
# dd if=./zfsloader of=/dev/ada0b bs=512 oseek=1024 conv=notrunc
only one copy of boot1 and zfsloader is needed to boot even if you use
mirror/raidz pool. surely you can write copies on each disk then you
can boot from another disk when disk failure.

6. install system on the zpool...

7. now the system can be booted with:
{1} ok boot disk0:b
if you defined devalias
{1} ok devalias disk0
disk0                    /pci@1c,600000/ide@2/disk@0,0

If you use mirrored or raidz type of zpool, do not forget to define
devalias for all used disks.


The only flaw of this zfs boot support for sparc64 is the lack of a
dedicate program to write zfsloader into ZFS Boot Block. Surely we
still can use dd to do this simply.
I do not think gpart is suitable to do such thing. Maybe it is
reasonable to have a command like:
# zpool installboot ./zfsloader tank

But such a command will be used only by sparc64 architecture since
other architectures does not use ZFS Boot Block.

Cheers,
Gavin Mu
Comment 4 marius 2012-03-04 18:06:52 UTC
On Mon, Feb 27, 2012 at 10:46:22PM +0800, Gavin Mu wrote:
> Here is the updated patch to support zfs boot fully. Now boot from
> mirror/raidz pool are also supported.
> 
> zfsboot is the enhancement of boot1. Instead of reading "/boot/loader"
> from UFS filesystem, it loads the ELF "zfsloader" program from the
> 3.5MB Boot Block of zpool in current vtoc8 partition (slice).
> 
> zfsloader tries to probe the zpool in current vtoc8 partition and if
> it is valid, it records the guid, then search all disks to find all
> zpools in the vtoc8 partitions with freebsd-zfs tag. zfsloader uses
> devalias "disk<n>" to find the disks, so devalias must be defined for
> all your bootable disks by OBP (aka. {ok} mode). then it boots from
> the zpool with the same guid.
> 
> If you use the whole disk as zpool, you can allocate all disk space
> into the first vtoc8 partition (for example, ada0a in FreeBSD) tag
> with freebsd-zfs to create zpool. It is same with creating zpool on
> the whole disk (ada0).
> 
> For reading from multiple disks, some ofw code are changed. The former
> code does not work when reading from multiple disks and I am not sure
> if it is possible and how to do this. (I googled but did not find more
> useful things). So I changed the code to close the current disk before
> a new disk is opened, and there will be only one disk opened
> simultaneously. I am not sure if this will slow the disk reading for
> booting from raidz pool. (It is several minutes slow on my V100
> machine to boot from raidz zpool).

Typically, opening and closing devices via OFW causes quite a delay,
the exact impact depends on the firmware version and the devices
involved though. Therefore, it would be advisable to keep using the
current approach of caching opened packages. In what way does this
fail with ZFS? Basically, IEEE 1275 just says that support for
opening a package more than once depends on the particular package
but nothing about concurrently opening different packages. Not
being able to concurrently open different packages also doesn't
make all that much of a sense as opening one package also means
to subsequentially open all the parents up to the root if not
already opened and I think to actually have tested opening disks
concurrently when writing the current code. Could this fail due
to one device actually being opened twice, once via the full path
and once via its alias?

Marius
Comment 5 Gavin Mu 2012-04-12 15:27:31 UTC
On Mon, Mar 5, 2012 at 2:06 AM, Marius Strobl <marius@alchemy.franken.de> wrote:
> Typically, opening and closing devices via OFW causes quite a delay,
> the exact impact depends on the firmware version and the devices
> involved though. Therefore, it would be advisable to keep using the
> current approach of caching opened packages. In what way does this
> fail with ZFS?
The error message on Fire V100 is: Fast Data Access MMU Miss

> Basically, IEEE 1275 just says that support for
> opening a package more than once depends on the particular package
> but nothing about concurrently opening different packages. Not
> being able to concurrently open different packages also doesn't
> make all that much of a sense as opening one package also means
> to subsequentially open all the parents up to the root if not
> already opened and I think to actually have tested opening disks
> concurrently when writing the current code. Could this fail due
> to one device actually being opened twice, once via the full path
> and once via its alias?
There is no such scene though the code lacks the checking for full
path/devalias.
I have tried many times to find the root cause but I think it is
difficult without open firmware knowledge.
currently I found that following scenes will cause this issue with my test code:
1. do OF_seek(ihandle_t a) just after OF_close(ihandle_t b). in real
world, OF_seek(a) is the step to read ZFS data just after OF_close()
another disk during zfs init/probe.
2. do OF_seek(ihandle_t a) just after OF_open("available controller
without disk"). For example there is no disk3 on my machine though
there is disk controller. OF_open("disk3:") will report:
Can't read disk label.
Can't open disk label package

in ofw_disk.c, OF_close() has been commented out for powerpc
architecture, and can not find detail reason from code history, so I
am thinking if we need also disable OF_close() for sparc64.

for OF_open("normal disk controller without disk") issue, I did not
find how to work around or fix yet.

Is there any documents about how this open firmware work? I googled
but can not find anything useful.

Regards,
Gavin Mu
Comment 6 marius 2012-04-22 21:32:11 UTC
On Thu, Apr 12, 2012 at 10:27:31PM +0800, Gavin Mu wrote:
> On Mon, Mar 5, 2012 at 2:06 AM, Marius Strobl <marius@alchemy.franken.de> wrote:
> > Typically, opening and closing devices via OFW causes quite a delay,
> > the exact impact depends on the firmware version and the devices
> > involved though. Therefore, it would be advisable to keep using the
> > current approach of caching opened packages. In what way does this
> > fail with ZFS?
> The error message on Fire V100 is: Fast Data Access MMU Miss
> 
> > Basically, IEEE 1275 just says that support for
> > opening a package more than once depends on the particular package
> > but nothing about concurrently opening different packages. Not
> > being able to concurrently open different packages also doesn't
> > make all that much of a sense as opening one package also means
> > to subsequentially open all the parents up to the root if not
> > already opened and I think to actually have tested opening disks
> > concurrently when writing the current code. Could this fail due
> > to one device actually being opened twice, once via the full path
> > and once via its alias?
> There is no such scene though the code lacks the checking for full
> path/devalias.
> I have tried many times to find the root cause but I think it is
> difficult without open firmware knowledge.
> currently I found that following scenes will cause this issue with my test code:
> 1. do OF_seek(ihandle_t a) just after OF_close(ihandle_t b). in real
> world, OF_seek(a) is the step to read ZFS data just after OF_close()
> another disk during zfs init/probe.
> 2. do OF_seek(ihandle_t a) just after OF_open("available controller
> without disk"). For example there is no disk3 on my machine though
> there is disk controller. OF_open("disk3:") will report:
> Can't read disk label.
> Can't open disk label package
> 
> in ofw_disk.c, OF_close() has been commented out for powerpc
> architecture, and can not find detail reason from code history, so I
> am thinking if we need also disable OF_close() for sparc64.

Hrm, some OFW implementations might have reference counting bugs,
causing OF_close() to also close some parent(s) when these in fact
are still used by another opened child device. Have you tried how
it works when just commenting out the OF_close() in ofwd_close() but
leaving the rest of ofw_disk.c as is? If that works, we probably
can add a cleanup handler which closes all opened disk devices
before leaving the loader, still taking advantage of caching opened
disks.

> 
> for OF_open("normal disk controller without disk") issue, I did not
> find how to work around or fix yet.

Currently, I can't think of a way to solve this with the available
OFW interfaces. Have you checked whether OpenSolaris includes the
source of the OFW ZFS loader bits and how it's done there or
generally how a Solaris instalaltion handles this (f.e. does it
create any additional aliases for ZFS providers and uses these
instead etc)?

> 
> Is there any documents about how this open firmware work? I googled
> but can not find anything useful.
> 

For the most part, there's just IEEE 1275. There once was a bit of
related information on http://playground.sun.com/1275/, which
unfortunately disappeared some time after Oracle took over.

Marius
Comment 7 dfilter service freebsd_committer freebsd_triage 2012-04-29 16:54:50 UTC
Author: marius
Date: Sun Apr 29 15:54:40 2012
New Revision: 234789
URL: http://svn.freebsd.org/changeset/base/234789

Log:
  Add multiple inclusion protection.
  
  PR:		165025
  Submitted by:	Gavin Mu
  MFC after:	1 week

Modified:
  head/sys/boot/common/bootstrap.h

Modified: head/sys/boot/common/bootstrap.h
==============================================================================
--- head/sys/boot/common/bootstrap.h	Sun Apr 29 13:37:32 2012	(r234788)
+++ head/sys/boot/common/bootstrap.h	Sun Apr 29 15:54:40 2012	(r234789)
@@ -26,6 +26,9 @@
  * $FreeBSD$
  */
 
+#ifndef _BOOTSTRAP_H_
+#define	_BOOTSTRAP_H_
+
 #include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/linker_set.h>
@@ -323,3 +326,5 @@ void	delay(int delay);
 void	dev_cleanup(void);
 
 time_t	time(time_t *tloc);
+
+#endif /* !_BOOTSTRAP_H_ */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 8 marius 2012-04-29 17:10:19 UTC
On Sun, Apr 22, 2012 at 08:40:13PM +0000, Marius Strobl wrote:
> The following reply was made to PR sparc64/165025; it has been noted by GNATS.
> 
> From: Marius Strobl <marius@alchemy.franken.de>
> To: Gavin Mu <gavin.mu@gmail.com>
> Cc: bug-followup@freebsd.org, Kurt Lidl <lidl@pix.net>
> Subject: Re: sparc64/165025: [PATCH] zfsboot support for sparc64
> Date: Sun, 22 Apr 2012 22:32:11 +0200
> 
>  On Thu, Apr 12, 2012 at 10:27:31PM +0800, Gavin Mu wrote:
>  > On Mon, Mar 5, 2012 at 2:06 AM, Marius Strobl <marius@alchemy.franken.de> wrote:
>  > > Typically, opening and closing devices via OFW causes quite a delay,
>  > > the exact impact depends on the firmware version and the devices
>  > > involved though. Therefore, it would be advisable to keep using the
>  > > current approach of caching opened packages. In what way does this
>  > > fail with ZFS?
>  > The error message on Fire V100 is: Fast Data Access MMU Miss
>  > 
>  > > Basically, IEEE 1275 just says that support for
>  > > opening a package more than once depends on the particular package
>  > > but nothing about concurrently opening different packages. Not
>  > > being able to concurrently open different packages also doesn't
>  > > make all that much of a sense as opening one package also means
>  > > to subsequentially open all the parents up to the root if not
>  > > already opened and I think to actually have tested opening disks
>  > > concurrently when writing the current code. Could this fail due
>  > > to one device actually being opened twice, once via the full path
>  > > and once via its alias?
>  > There is no such scene though the code lacks the checking for full
>  > path/devalias.
>  > I have tried many times to find the root cause but I think it is
>  > difficult without open firmware knowledge.
>  > currently I found that following scenes will cause this issue with my test code:
>  > 1. do OF_seek(ihandle_t a) just after OF_close(ihandle_t b). in real
>  > world, OF_seek(a) is the step to read ZFS data just after OF_close()
>  > another disk during zfs init/probe.
>  > 2. do OF_seek(ihandle_t a) just after OF_open("available controller
>  > without disk"). For example there is no disk3 on my machine though
>  > there is disk controller. OF_open("disk3:") will report:
>  > Can't read disk label.
>  > Can't open disk label package
>  > 
>  > in ofw_disk.c, OF_close() has been commented out for powerpc
>  > architecture, and can not find detail reason from code history, so I
>  > am thinking if we need also disable OF_close() for sparc64.
>  
>  Hrm, some OFW implementations might have reference counting bugs,
>  causing OF_close() to also close some parent(s) when these in fact
>  are still used by another opened child device. Have you tried how
>  it works when just commenting out the OF_close() in ofwd_close() but
>  leaving the rest of ofw_disk.c as is? If that works, we probably
>  can add a cleanup handler which closes all opened disk devices
>  before leaving the loader, still taking advantage of caching opened
>  disks.
>  

With the machines I have at hand, I can't reproduce this problem,
i.e. ofw_disk.c as is works just fine for booting from a mirror.
This suggests that what you are seeing actually is a bug in the
specific firmware implementation rather than a general limitation
imposed by OFW. Could you please give the following patch a try?
It implements what I've described above, i.e. combines both caching
opened devices and properly closing all opened disks when leaving
the loader.
http://people.freebsd.org/~marius/ofw_disk_close_on_cleanup.diff

Marius
Comment 9 Gavin Mu 2012-04-30 14:24:46 UTC
On Mon, Apr 30, 2012 at 12:10 AM, Marius Strobl
<marius@alchemy.franken.de> wrote:
> On Sun, Apr 22, 2012 at 08:40:13PM +0000, Marius Strobl wrote:
>> The following reply was made to PR sparc64/165025; it has been noted by =
GNATS.
>>
>> From: Marius Strobl <marius@alchemy.franken.de>
>> To: Gavin Mu <gavin.mu@gmail.com>
>> Cc: bug-followup@freebsd.org, Kurt Lidl <lidl@pix.net>
>> Subject: Re: sparc64/165025: [PATCH] zfsboot support for sparc64
>> Date: Sun, 22 Apr 2012 22:32:11 +0200
>>
>> =A0On Thu, Apr 12, 2012 at 10:27:31PM +0800, Gavin Mu wrote:
>> =A0> On Mon, Mar 5, 2012 at 2:06 AM, Marius Strobl <marius@alchemy.frank=
en.de> wrote:
>> =A0> > Typically, opening and closing devices via OFW causes quite a del=
ay,
>> =A0> > the exact impact depends on the firmware version and the devices
>> =A0> > involved though. Therefore, it would be advisable to keep using t=
he
>> =A0> > current approach of caching opened packages. In what way does thi=
s
>> =A0> > fail with ZFS?
>> =A0> The error message on Fire V100 is: Fast Data Access MMU Miss
>> =A0>
>> =A0> > Basically, IEEE 1275 just says that support for
>> =A0> > opening a package more than once depends on the particular packag=
e
>> =A0> > but nothing about concurrently opening different packages. Not
>> =A0> > being able to concurrently open different packages also doesn't
>> =A0> > make all that much of a sense as opening one package also means
>> =A0> > to subsequentially open all the parents up to the root if not
>> =A0> > already opened and I think to actually have tested opening disks
>> =A0> > concurrently when writing the current code. Could this fail due
>> =A0> > to one device actually being opened twice, once via the full path
>> =A0> > and once via its alias?
>> =A0> There is no such scene though the code lacks the checking for full
>> =A0> path/devalias.
>> =A0> I have tried many times to find the root cause but I think it is
>> =A0> difficult without open firmware knowledge.
>> =A0> currently I found that following scenes will cause this issue with =
my test code:
>> =A0> 1. do OF_seek(ihandle_t a) just after OF_close(ihandle_t b). in rea=
l
>> =A0> world, OF_seek(a) is the step to read ZFS data just after OF_close(=
)
>> =A0> another disk during zfs init/probe.
>> =A0> 2. do OF_seek(ihandle_t a) just after OF_open("available controller
>> =A0> without disk"). For example there is no disk3 on my machine though
>> =A0> there is disk controller. OF_open("disk3:") will report:
>> =A0> Can't read disk label.
>> =A0> Can't open disk label package
>> =A0>
>> =A0> in ofw_disk.c, OF_close() has been commented out for powerpc
>> =A0> architecture, and can not find detail reason from code history, so =
I
>> =A0> am thinking if we need also disable OF_close() for sparc64.
>>
>> =A0Hrm, some OFW implementations might have reference counting bugs,
>> =A0causing OF_close() to also close some parent(s) when these in fact
>> =A0are still used by another opened child device. Have you tried how
>> =A0it works when just commenting out the OF_close() in ofwd_close() but
>> =A0leaving the rest of ofw_disk.c as is? If that works, we probably
>> =A0can add a cleanup handler which closes all opened disk devices
>> =A0before leaving the loader, still taking advantage of caching opened
>> =A0disks.
>>
>
> With the machines I have at hand, I can't reproduce this problem,
> i.e. ofw_disk.c as is works just fine for booting from a mirror.
> This suggests that what you are seeing actually is a bug in the
> specific firmware implementation rather than a general limitation
> imposed by OFW. Could you please give the following patch a try?
> It implements what I've described above, i.e. combines both caching
> opened devices and properly closing all opened disks when leaving
> the loader.
> http://people.freebsd.org/~marius/ofw_disk_close_on_cleanup.diff
>
> Marius
>

I am sorry that I have lost the access to the sparc machines since I
am moving to a new job.
I checked your modification and there should be an issue of opening a
slice twice, one by the real dev path and the other by devalias.
ofw_disk can not deal with such scene.
My testing machine is Sun Fire V100, a very old machine, and with the
latest firmware (surely it is also very old though).
I am not sure if we can still find same machine to do the testing. or
can we call for some testers on several different hardware models
before committing the code?

Regards,
Gavin Mu
Comment 10 dfilter service freebsd_committer freebsd_triage 2012-05-01 17:38:50 UTC
Author: marius
Date: Tue May  1 16:38:33 2012
New Revision: 234897
URL: http://svn.freebsd.org/changeset/base/234897

Log:
  Add a command for showing the heap usage.
  
  PR:		165025
  Submitted by:	Gavin Mu
  MFC after:	1 week

Modified:
  head/sys/boot/sparc64/loader/main.c

Modified: head/sys/boot/sparc64/loader/main.c
==============================================================================
--- head/sys/boot/sparc64/loader/main.c	Tue May  1 16:18:38 2012	(r234896)
+++ head/sys/boot/sparc64/loader/main.c	Tue May  1 16:38:33 2012	(r234897)
@@ -800,6 +800,18 @@ main(int (*openfirm)(void *))
 	return (1);
 }
 
+COMMAND_SET(heap, "heap", "show heap usage", command_heap);
+
+static int
+command_heap(int argc, char *argv[])
+{
+
+	mallocstats();
+	printf("heap base at %p, top at %p, upper limit at %p\n", heapva,
+	    sbrk(0), heapva + HEAPSZ);
+	return(CMD_OK);
+}
+
 COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
 
 static int
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 11 dfilter service freebsd_committer freebsd_triage 2012-05-01 18:16:12 UTC
Author: marius
Date: Tue May  1 17:16:01 2012
New Revision: 234898
URL: http://svn.freebsd.org/changeset/base/234898

Log:
  Add initial support for booting from ZFS on sparc64. At least on Sun Fire
  V100, the firmware is known to be broken and not allowing to simultaneously
  open disk devices, causing attempts to boot from a mirror or RAIDZ to cause
  a crash. This will be worked around later. The firmwares of newer sun4u models
  don't seem to exhibit this problem though.
  
  Steps for ZFS booting:
  
  1. create VTOC8 label
  # gpart create -s vtoc8 da0
  
  2. add partitions, f.e.:
  # gpart add -t freebsd-zfs -s 60g da0
  # gpart add -t freebsd-swap da0
  resulting in something like:
  # gpart show
  =>        0  143331930  da0  VTOC8  (68G)
            0  125821080    1  freebsd-zfs  (60G)
    125821080   17510850    2  freebsd-swap  (8.4G)
  
  3. create zpool
  # zpool create bunker da0a
  or for mirror/RAIDZ (after preparing additional disks as in steps 1. + 2.):
  # zpool create bunker mirror da0a da1a
  # zpool create bunker raidz da0a da1a da2a ...
  
  4. set bootfs
  # zpool set bootfs=bunker bunker
  
  5. install zfsboot
  # zpool export bunker
  # gpart bootcode -p /boot/zfsboot da0
  
  6. write zfsloader to the ZFS Boot Block (so far, there's no dedicated tool
  for this, so dd(1) has to be used for this purpose)
  When using mirror/RAIDZ, step 4. and the dd(1) invocation should be repeated
  for the additional disks in order to be able to boot from another disk in
  case of failure.
  # sysctl kern.geom.debugflags=0x10
  # dd if=/boot/zfsloader of=/dev/da0a bs=512 oseek=1024 conv=notrunc
  # zpool import bunker
  
  7. install system on ZFS filesystem
  Don't forget to set 'zfs_load="YES"' and vfs.root.mountfrom="zfs:bunker" in
  loader.conf as well as 'zfs_enable="YES"'in rc.conf.
  
  8. copy zpool.cache to the ZFS filesystem
  cp -p /boot/zfs/zpool.cache /bunker/boot/zfs/zpool.cache
  
  9. set mountpoint
  # zfs set mountpoint=/ bunker
  
  10. Now, given that aliases for all disks in the zpool exists (check with
  the `devalias` command on the boot monitor prompt) and disk0 corresponds
  to da0 (likewise for additional disks), the system can be booted from the
  ZFS with:
  {1} ok boot disk0
  
  PR:             165025
  Submitted by:   Gavin Mu

Added:
  head/sys/boot/sparc64/zfsboot/
  head/sys/boot/sparc64/zfsboot/Makefile   (contents, props changed)
  head/sys/boot/sparc64/zfsloader/
  head/sys/boot/sparc64/zfsloader/Makefile   (contents, props changed)
Modified:
  head/sys/boot/ofw/libofw/devicename.c
  head/sys/boot/sparc64/Makefile
  head/sys/boot/sparc64/boot1/Makefile
  head/sys/boot/sparc64/boot1/boot1.c
  head/sys/boot/sparc64/loader/Makefile
  head/sys/boot/sparc64/loader/main.c
  head/sys/boot/zfs/zfs.c

Modified: head/sys/boot/ofw/libofw/devicename.c
==============================================================================
--- head/sys/boot/ofw/libofw/devicename.c	Tue May  1 16:38:33 2012	(r234897)
+++ head/sys/boot/ofw/libofw/devicename.c	Tue May  1 17:16:01 2012	(r234898)
@@ -28,6 +28,8 @@
 __FBSDID("$FreeBSD$");
 
 #include <stand.h>
+
+#include "bootstrap.h"
 #include "libofw.h"
 
 static int ofw_parsedev(struct ofw_devdesc **, const char *, const char **);
@@ -76,6 +78,7 @@ ofw_parsedev(struct ofw_devdesc **dev, c
     phandle_t		handle;
     const char		*p;
     const char		*s;
+    char		*ep;
     char		name[256];
     char		type[64];
     int			len;
@@ -87,9 +90,10 @@ ofw_parsedev(struct ofw_devdesc **dev, c
 	len = s - devspec;
 	bcopy(devspec, name, len);
 	name[len] = '\0';
-	if ((handle = OF_finddevice(name)) == -1)
-	    break;
-	if (OF_getprop(handle, "device_type", type, sizeof(type)) == -1)
+	if ((handle = OF_finddevice(name)) == -1) {
+	    bcopy(name, type, len);
+	    type[len] = '\0';
+	} else if (OF_getprop(handle, "device_type", type, sizeof(type)) == -1)
 	    continue;
 	for (i = 0; (dv = devsw[i]) != NULL; i++) {
 	    if (strncmp(dv->dv_name, type, strlen(dv->dv_name)) == 0)
@@ -109,6 +113,18 @@ found:
     strcpy(idev->d_path, name);
     idev->d_dev = dv;
     idev->d_type = dv->dv_type;
+    if (idev->d_type == DEVT_ZFS) {
+	idev->d_unit = 0;
+	p = name + strlen(dv->dv_name);
+	if (*p && (*p != ':')) {
+	    idev->d_unit = strtol(p, &ep, 0);
+	    if (ep == p) {
+		free(idev);
+		return (EUNIT);
+	    }
+	}
+    }
+
     if (dev == NULL) {
 	free(idev);
     } else {

Modified: head/sys/boot/sparc64/Makefile
==============================================================================
--- head/sys/boot/sparc64/Makefile	Tue May  1 16:38:33 2012	(r234897)
+++ head/sys/boot/sparc64/Makefile	Tue May  1 17:16:01 2012	(r234898)
@@ -1,5 +1,5 @@
 # $FreeBSD$
 
-SUBDIR=	boot1 loader
+SUBDIR=	boot1 loader zfsboot zfsloader
 
 .include <bsd.subdir.mk>

Modified: head/sys/boot/sparc64/boot1/Makefile
==============================================================================
--- head/sys/boot/sparc64/boot1/Makefile	Tue May  1 16:38:33 2012	(r234897)
+++ head/sys/boot/sparc64/boot1/Makefile	Tue May  1 17:16:01 2012	(r234898)
@@ -3,22 +3,23 @@
 PROG=	boot1.elf
 INTERNALPROG=
 NO_MAN=
-FILES=	boot1
+FILES?=	boot1
 SRCS=	_start.s boot1.c
+CLEANFILES+=boot1 boot1.aout
 
 BOOTBLOCKBASE= 0x4000
 
-CFLAGS=	-mcmodel=medlow -Os -I${.CURDIR}/../../common
+CFLAGS+=-mcmodel=medlow -Os -I${.CURDIR}/../../common
 LDFLAGS=-Ttext ${BOOTBLOCKBASE} -Wl,-N
 
 # Construct boot1. sunlabel expects it to contain zeroed-out space for the
 # label, and to be of the correct size.
 boot1: boot1.aout
+	@set -- `ls -l boot1.aout`; x=$$((7680-$$5)); \
+	    echo "$$x bytes available"; test $$x -ge 0
 	dd if=/dev/zero of=${.TARGET} bs=512 count=16
 	dd if=boot1.aout of=${.TARGET} bs=512 oseek=1 conv=notrunc
 
-CLEANFILES= boot1.aout
-
 boot1.aout: boot1.elf
 	elf2aout -o ${.TARGET} ${.ALLSRC}
 

Modified: head/sys/boot/sparc64/boot1/boot1.c
==============================================================================
--- head/sys/boot/sparc64/boot1/boot1.c	Tue May  1 16:38:33 2012	(r234897)
+++ head/sys/boot/sparc64/boot1/boot1.c	Tue May  1 17:16:01 2012	(r234898)
@@ -20,11 +20,13 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/dirent.h>
+
 #include <machine/elf.h>
 #include <machine/stdarg.h>
 
-#define _PATH_LOADER	"/boot/loader"
-#define _PATH_KERNEL	"/boot/kernel/kernel"
+#define	_PATH_LOADER	"/boot/loader"
+#define	_PATH_KERNEL	"/boot/kernel/kernel"
+#define	READ_BUF_SIZE	8192
 
 typedef int putc_func_t(char c, void *arg);
 typedef int32_t ofwh_t;
@@ -45,17 +47,21 @@ static ofwh_t bootdev;
 static uint32_t fs_off;
 
 int main(int ac, char **av);
-
 static void exit(int) __dead2;
-static void load(const char *);
-static int dskread(void *, u_int64_t, int);
-
 static void usage(void);
 
+#ifdef ZFSBOOT
+static void loadzfs(void);
+static int zbread(char *buf, off_t off, size_t bytes);
+#else
+static void load(const char *);
+#endif
+
 static void bcopy(const void *src, void *dst, size_t len);
 static void bzero(void *b, size_t len);
 
 static int mount(const char *device);
+static int dskread(void *buf, u_int64_t lba, int nblk);
 
 static void panic(const char *fmt, ...) __dead2;
 static int printf(const char *fmt, ...);
@@ -312,8 +318,6 @@ strcmp(const char *s1, const char *s2)
 	return ((u_char)*s1 - (u_char)*s2);
 }
 
-#include "ufsread.c"
-
 int
 main(int ac, char **av)
 {
@@ -335,14 +339,22 @@ main(int ac, char **av)
 		}
 	}
 
-	printf(" \n>> FreeBSD/sparc64 boot block\n"
-	"   Boot path:   %s\n"
-	"   Boot loader: %s\n", bootpath, path);
+#ifdef ZFSBOOT
+	printf(" \n>> FreeBSD/sparc64 ZFS boot block\n    Boot path:   %s\n",
+	    bootpath);
+#else
+	printf(" \n>> FreeBSD/sparc64 boot block\n    Boot path:   %s\n"
+	    "   Boot loader: %s\n", "", bootpath, path);
+#endif
 
 	if (mount(bootpath) == -1)
 		panic("mount");
 
+#ifdef ZFSBOOT
+	loadzfs();
+#else
 	load(path);
+#endif
 	return (1);
 }
 
@@ -361,24 +373,86 @@ exit(int code)
 	ofw_exit();
 }
 
-static struct dmadat __dmadat;
+#ifdef ZFSBOOT
+
+#define	VDEV_BOOT_OFFSET	(2 * 256 * 1024)
+static char zbuf[READ_BUF_SIZE];
 
 static int
-mount(const char *device)
+zbread(char *buf, off_t off, size_t bytes)
 {
+	size_t len;
+	off_t poff;
+	off_t soff;
+	char *p;
+	unsigned int nb;
+	unsigned int lb;
 
-	dmadat = &__dmadat;
-	if ((bootdev = ofw_open(device)) == -1) {
-		printf("mount: can't open device\n");
-		return (-1);
+	p = buf;
+	soff = VDEV_BOOT_OFFSET + off;
+	lb = (soff + bytes + DEV_BSIZE - 1) / DEV_BSIZE;
+	poff = soff;
+	while (poff < soff + bytes) {
+		nb = lb - poff / DEV_BSIZE;
+		if (nb > READ_BUF_SIZE / DEV_BSIZE)
+			nb = READ_BUF_SIZE / DEV_BSIZE;
+		if (dskread(zbuf, poff / DEV_BSIZE, nb))
+			break;
+		if ((poff / DEV_BSIZE + nb) * DEV_BSIZE > soff + bytes)
+			len = soff + bytes - poff;
+		else
+			len = (poff / DEV_BSIZE + nb) * DEV_BSIZE - poff;
+		memcpy(p, zbuf + poff % DEV_BSIZE, len);
+		p += len;
+		poff += len;
 	}
-	if (fsread(0, NULL, 0)) {
-		printf("mount: can't read superblock\n");
-		return (-1);
+	return (poff - soff);
+}
+
+static void
+loadzfs(void)
+{
+	Elf64_Ehdr eh;
+	Elf64_Phdr ph;
+	caddr_t p;
+	ino_t ino;
+	int i;
+
+	if (zbread((char *)&eh, 0, sizeof(eh)) != sizeof(eh)) {
+		printf("Can't read elf header\n");
+		return;
 	}
-	return (0);
+	if (!IS_ELF(eh)) {
+		printf("Not an ELF file\n");
+		return;
+	}
+	for (i = 0; i < eh.e_phnum; i++) {
+		fs_off = eh.e_phoff + i * eh.e_phentsize;
+		if (zbread((char *)&ph, fs_off, sizeof(ph)) != sizeof(ph)) {
+			printf("Can't read program header %d\n", i);
+			return;
+		}
+		if (ph.p_type != PT_LOAD)
+			continue;
+		fs_off = ph.p_offset;
+		p = (caddr_t)ph.p_vaddr;
+		if (zbread(p, fs_off, ph.p_filesz) != ph.p_filesz) {
+			printf("Can't read content of section %d\n", i);
+			return;
+		}
+		if (ph.p_filesz != ph.p_memsz)
+			bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz);
+	}
+	ofw_close(bootdev);
+	(*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw);
 }
 
+#else
+
+#include "ufsread.c"
+
+static struct dmadat __dmadat;
+
 static void
 load(const char *fname)
 {
@@ -421,6 +495,26 @@ load(const char *fname)
 	(*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw);
 }
 
+#endif /* ZFSBOOT */
+
+static int
+mount(const char *device)
+{
+
+	if ((bootdev = ofw_open(device)) == -1) {
+		printf("mount: can't open device\n");
+		return (-1);
+	}
+#ifndef ZFSBOOT
+	dmadat = &__dmadat;
+	if (fsread(0, NULL, 0)) {
+		printf("mount: can't read superblock\n");
+		return (-1);
+	}
+#endif
+	return (0);
+}
+
 static int
 dskread(void *buf, u_int64_t lba, int nblk)
 {

Modified: head/sys/boot/sparc64/loader/Makefile
==============================================================================
--- head/sys/boot/sparc64/loader/Makefile	Tue May  1 16:38:33 2012	(r234897)
+++ head/sys/boot/sparc64/loader/Makefile	Tue May  1 17:16:01 2012	(r234898)
@@ -3,8 +3,8 @@
 .include <bsd.own.mk>
 MK_SSP=		no
 
-PROG=		loader
-NEWVERSWHAT=	"bootstrap loader" sparc64
+PROG?=		loader
+NEWVERSWHAT?=	"bootstrap loader" sparc64
 INSTALLFLAGS=	-b
 
 # Architecture-specific loader code
@@ -13,12 +13,17 @@ SRCS=		locore.S main.c metadata.c vers.c
 LOADER_DISK_SUPPORT?=	yes
 LOADER_UFS_SUPPORT?=	yes
 LOADER_CD9660_SUPPORT?=	yes
+LOADER_ZFS_SUPPORT?=	no
 LOADER_NET_SUPPORT?=	yes
 LOADER_NFS_SUPPORT?=	yes
 LOADER_TFTP_SUPPORT?=	yes
 LOADER_GZIP_SUPPORT?=	yes
 LOADER_BZIP2_SUPPORT?=	no
+LOADER_DEBUG?=		no
 
+.if ${LOADER_DEBUG} == "yes"
+CFLAGS+=	-DLOADER_DEBUG
+.endif
 .if ${LOADER_DISK_SUPPORT} == "yes"
 CFLAGS+=	-DLOADER_DISK_SUPPORT
 .endif
@@ -28,6 +33,11 @@ CFLAGS+=	-DLOADER_UFS_SUPPORT
 .if ${LOADER_CD9660_SUPPORT} == "yes"
 CFLAGS+=	-DLOADER_CD9660_SUPPORT
 .endif
+.if ${LOADER_ZFS_SUPPORT} == "yes"
+CFLAGS+=	-DLOADER_ZFS_SUPPORT
+CFLAGS+=	-I${.CURDIR}/../../zfs
+CFLAGS+=	-I${.CURDIR}/../../../cddl/boot/zfs
+.endif
 .if ${LOADER_GZIP_SUPPORT} == "yes"
 CFLAGS+=	-DLOADER_GZIP_SUPPORT
 .endif
@@ -47,7 +57,8 @@ CFLAGS+=	-DLOADER_TFTP_SUPPORT
 .if ${MK_FORTH} != "no"
 # Enable BootForth
 BOOT_FORTH=	yes
-CFLAGS+=	-DBOOT_FORTH -I${.CURDIR}/../../ficl -I${.CURDIR}/../../ficl/sparc64
+CFLAGS+=	-DBOOT_FORTH -I${.CURDIR}/../../ficl
+CFLAGS+=	-I${.CURDIR}/../../ficl/sparc64
 LIBFICL=	${.OBJDIR}/../../ficl/libficl.a
 .endif
 
@@ -75,8 +86,9 @@ CFLAGS+=	-I${.CURDIR}/../../../../lib/li
 DPADD=		${LIBFICL} ${LIBOFW} ${LIBSTAND}
 LDADD=		${LIBFICL} ${LIBOFW} -lstand
 
-vers.c:	${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version
-	sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT}
+vers.c:	${.CURDIR}/../../common/newvers.sh ${.CURDIR}/../loader/version
+	sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/../loader/version \
+	    ${NEWVERSWHAT}
 
 loader.help: help.common help.sparc64
 	cat ${.ALLSRC} | \

Modified: head/sys/boot/sparc64/loader/main.c
==============================================================================
--- head/sys/boot/sparc64/loader/main.c	Tue May  1 16:38:33 2012	(r234897)
+++ head/sys/boot/sparc64/loader/main.c	Tue May  1 17:16:01 2012	(r234898)
@@ -51,6 +51,9 @@ __FBSDID("$FreeBSD$");
 #include <sys/linker.h>
 #include <sys/queue.h>
 #include <sys/types.h>
+#ifdef LOADER_ZFS_SUPPORT
+#include <sys/vtoc.h>
+#endif
 
 #include <vm/vm.h>
 #include <machine/asi.h>
@@ -143,6 +146,11 @@ static vm_offset_t heapva;
 
 static phandle_t root;
 
+#ifdef LOADER_ZFS_SUPPORT
+static int zfs_dev_init(void);
+#include "zfs.c"
+#endif
+
 /*
  * Machine dependent structures that the machine independent
  * loader part uses.
@@ -154,6 +162,9 @@ struct devsw *devsw[] = {
 #ifdef LOADER_NET_SUPPORT
 	&netdev,
 #endif
+#ifdef LOADER_ZFS_SUPPORT
+	&zfs_dev,
+#endif
 	0
 };
 struct arch_switch archsw;
@@ -166,6 +177,7 @@ struct file_format *file_formats[] = {
 	&sparc64_elf,
 	0
 };
+
 struct fs_ops *file_system[] = {
 #ifdef LOADER_UFS_SUPPORT
 	&ufs_fsops,
@@ -173,6 +185,9 @@ struct fs_ops *file_system[] = {
 #ifdef LOADER_CD9660_SUPPORT
 	&cd9660_fsops,
 #endif
+#ifdef LOADER_ZFS_SUPPORT
+	&zfs_fsops,
+#endif
 #ifdef LOADER_ZIP_SUPPORT
 	&zipfs_fsops,
 #endif
@@ -721,6 +736,82 @@ tlb_init_sun4u(void)
 		panic("%s: can't allocate TLB store", __func__);
 }
 
+#ifdef LOADER_ZFS_SUPPORT
+
+static int
+zfs_dev_init(void)
+{
+	struct vtoc8 vtoc;
+	char devname[512];
+	spa_t *spa;
+	vdev_t *vdev;
+	uint64_t guid;
+	int fd, part, unit;
+
+	zfs_init();
+
+	guid = 0;
+	/* Get the GUID of the ZFS pool on the boot device. */
+	fd = open(getenv("currdev"), O_RDONLY);
+	if (fd != -1) {
+		if (vdev_probe(vdev_read, (void *)(uintptr_t) fd, &spa) == 0)
+			guid = spa->spa_guid;
+		close(fd);
+	}
+
+	/* Clean up the environment to let ZFS work. */
+	while ((vdev = STAILQ_FIRST(&zfs_vdevs)) != NULL) {
+		STAILQ_REMOVE_HEAD(&zfs_vdevs, v_alllink);
+		free(vdev);
+	}
+	while ((spa = STAILQ_FIRST(&zfs_pools)) != NULL) {
+		STAILQ_REMOVE_HEAD(&zfs_pools, spa_link);
+		free(spa);
+	}
+
+	for (unit = 0; unit < MAXBDDEV; unit++) {
+		/* Find freebsd-zfs slices in the VTOC. */
+		sprintf(devname, "disk%d:", unit);
+		fd = open(devname, O_RDONLY);
+		if (fd == -1)
+			continue;
+		lseek(fd, 0, SEEK_SET);
+		if (read(fd, &vtoc, sizeof(vtoc)) != sizeof(vtoc)) {
+			close(fd);
+			continue;
+		}
+		close(fd);
+
+		for (part = 0; part < 8; part++) {
+			if (part == 2 || vtoc.part[part].tag !=
+			     VTOC_TAG_FREEBSD_ZFS)
+				continue;
+			sprintf(devname, "disk%d:%c", unit, part + 'a');
+			fd = open(devname, O_RDONLY);
+			if (fd == -1)
+				break;
+
+			if (vdev_probe(vdev_read, (void*)(uintptr_t) fd, 0))
+				close(fd);
+		}
+	}
+
+	if (guid != 0) {
+		unit = zfs_guid_to_unit(guid);
+		if (unit >= 0) {
+			/* Update the environment for ZFS. */
+			sprintf(devname, "zfs%d", unit);
+			env_setenv("currdev", EV_VOLATILE, devname,
+			   ofw_setcurrdev, env_nounset);
+			env_setenv("loaddev", EV_VOLATILE, devname,
+			   env_noset, env_nounset);
+		}
+	}
+	return (0);
+}
+
+#endif /* LOADER_ZFS_SUPPORT */
+
 int
 main(int (*openfirm)(void *))
 {
@@ -756,14 +847,6 @@ main(int (*openfirm)(void *))
 	mmu_ops->tlb_init();
 
 	/*
-	 * Initialize devices.
-	 */
-	for (dp = devsw; *dp != 0; dp++) {
-		if ((*dp)->dv_init != 0)
-			(*dp)->dv_init();
-	}
-
-	/*
 	 * Set up the current device.
 	 */
 	OF_getprop(chosen, "bootpath", bootpath, sizeof(bootpath));
@@ -780,7 +863,8 @@ main(int (*openfirm)(void *))
 	 * needs to be altered.
 	 */
 	if (bootpath[strlen(bootpath) - 2] == ':' &&
-	    bootpath[strlen(bootpath) - 1] == 'f') {
+	    bootpath[strlen(bootpath) - 1] == 'f' &&
+	    strstr(bootpath, "cdrom")) {
 		bootpath[strlen(bootpath) - 1] = 'a';
 		printf("Boot path set to %s\n", bootpath);
 	}
@@ -790,6 +874,13 @@ main(int (*openfirm)(void *))
 	env_setenv("loaddev", EV_VOLATILE, bootpath,
 	    env_noset, env_nounset);
 
+	/*
+	 * Initialize devices.
+	 */
+	for (dp = devsw; *dp != 0; dp++)
+		if ((*dp)->dv_init != 0)
+			(*dp)->dv_init();
+
 	printf("\n");
 	printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
 	printf("(%s, %s)\n", bootprog_maker, bootprog_date);

Added: head/sys/boot/sparc64/zfsboot/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/boot/sparc64/zfsboot/Makefile	Tue May  1 17:16:01 2012	(r234898)
@@ -0,0 +1,13 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../boot1
+
+PROGNAME=	zfsboot
+CFLAGS+=	-DZFSBOOT
+FILES=		zfsboot
+CLEANFILES+=	zfsboot
+
+zfsboot: boot1
+	ln -s ${.ALLSRC} ${.TARGET}
+
+.include "${.CURDIR}/../boot1/Makefile"

Added: head/sys/boot/sparc64/zfsloader/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/boot/sparc64/zfsloader/Makefile	Tue May  1 17:16:01 2012	(r234898)
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../loader
+
+PROG=		zfsloader
+NEWVERSWHAT=	"ZFS enabled bootstrap loader" sparc64
+LOADER_ZFS_SUPPORT=yes
+
+.include "${.CURDIR}/../loader/Makefile"

Modified: head/sys/boot/zfs/zfs.c
==============================================================================
--- head/sys/boot/zfs/zfs.c	Tue May  1 16:38:33 2012	(r234897)
+++ head/sys/boot/zfs/zfs.c	Tue May  1 17:16:01 2012	(r234898)
@@ -399,6 +399,7 @@ zfs_guid_to_unit(uint64_t guid)
 	return (-1);
 }
 
+#if defined(__amd64__) || defined(__i386__)
 static int
 zfs_dev_init(void) 
 {
@@ -441,6 +442,7 @@ zfs_dev_init(void) 
 
 	return (0);
 }
+#endif
 
 /*
  * Print information about ZFS pools
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 12 dfilter service freebsd_committer freebsd_triage 2012-05-25 15:54:24 UTC
Author: marius
Date: Fri May 25 14:54:12 2012
New Revision: 235995
URL: http://svn.freebsd.org/changeset/base/235995

Log:
  MFC: r234789
  
  Add multiple inclusion protection.
  
  PR:		165025
  Submitted by:	Gavin Mu

Modified:
  stable/9/sys/boot/common/bootstrap.h
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/amd64/include/xen/   (props changed)
  stable/9/sys/boot/   (props changed)
  stable/9/sys/boot/i386/efi/   (props changed)
  stable/9/sys/boot/ia64/efi/   (props changed)
  stable/9/sys/boot/ia64/ski/   (props changed)
  stable/9/sys/boot/powerpc/boot1.chrp/   (props changed)
  stable/9/sys/boot/powerpc/ofw/   (props changed)
  stable/9/sys/cddl/contrib/opensolaris/   (props changed)
  stable/9/sys/conf/   (props changed)
  stable/9/sys/contrib/dev/acpica/   (props changed)
  stable/9/sys/contrib/octeon-sdk/   (props changed)
  stable/9/sys/contrib/pf/   (props changed)
  stable/9/sys/contrib/x86emu/   (props changed)
  stable/9/sys/dev/   (props changed)
  stable/9/sys/dev/e1000/   (props changed)
  stable/9/sys/dev/ixgbe/   (props changed)
  stable/9/sys/fs/   (props changed)
  stable/9/sys/fs/ntfs/   (props changed)
  stable/9/sys/modules/   (props changed)

Modified: stable/9/sys/boot/common/bootstrap.h
==============================================================================
--- stable/9/sys/boot/common/bootstrap.h	Fri May 25 14:52:05 2012	(r235994)
+++ stable/9/sys/boot/common/bootstrap.h	Fri May 25 14:54:12 2012	(r235995)
@@ -26,6 +26,9 @@
  * $FreeBSD$
  */
 
+#ifndef _BOOTSTRAP_H_
+#define	_BOOTSTRAP_H_
+
 #include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/linker_set.h>
@@ -323,3 +326,5 @@ void	delay(int delay);
 void	dev_cleanup(void);
 
 time_t	time(time_t *tloc);
+
+#endif /* !_BOOTSTRAP_H_ */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 13 dfilter service freebsd_committer freebsd_triage 2012-05-25 15:54:43 UTC
Author: marius
Date: Fri May 25 14:54:18 2012
New Revision: 235996
URL: http://svn.freebsd.org/changeset/base/235996

Log:
  MFC: r234789
  
  Add multiple inclusion protection.
  
  PR:		165025
  Submitted by:	Gavin Mu

Modified:
  stable/8/sys/boot/common/bootstrap.h
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/boot/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/e1000/   (props changed)

Modified: stable/8/sys/boot/common/bootstrap.h
==============================================================================
--- stable/8/sys/boot/common/bootstrap.h	Fri May 25 14:54:12 2012	(r235995)
+++ stable/8/sys/boot/common/bootstrap.h	Fri May 25 14:54:18 2012	(r235996)
@@ -26,6 +26,9 @@
  * $FreeBSD$
  */
 
+#ifndef _BOOTSTRAP_H_
+#define	_BOOTSTRAP_H_
+
 #include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/linker_set.h>
@@ -307,3 +310,5 @@ void	delay(int delay);
 void	dev_cleanup(void);
 
 time_t	time(time_t *tloc);
+
+#endif /* !_BOOTSTRAP_H_ */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 14 dfilter service freebsd_committer freebsd_triage 2012-05-25 15:57:20 UTC
Author: marius
Date: Fri May 25 14:57:01 2012
New Revision: 235997
URL: http://svn.freebsd.org/changeset/base/235997

Log:
  MFC: r234897
  
  Add a command for showing the heap usage.
  
  PR:		165025
  Submitted by:	Gavin Mu

Modified:
  stable/9/sys/boot/sparc64/loader/main.c
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/amd64/include/xen/   (props changed)
  stable/9/sys/boot/   (props changed)
  stable/9/sys/boot/i386/efi/   (props changed)
  stable/9/sys/boot/ia64/efi/   (props changed)
  stable/9/sys/boot/ia64/ski/   (props changed)
  stable/9/sys/boot/powerpc/boot1.chrp/   (props changed)
  stable/9/sys/boot/powerpc/ofw/   (props changed)
  stable/9/sys/cddl/contrib/opensolaris/   (props changed)
  stable/9/sys/conf/   (props changed)
  stable/9/sys/contrib/dev/acpica/   (props changed)
  stable/9/sys/contrib/octeon-sdk/   (props changed)
  stable/9/sys/contrib/pf/   (props changed)
  stable/9/sys/contrib/x86emu/   (props changed)
  stable/9/sys/dev/   (props changed)
  stable/9/sys/dev/e1000/   (props changed)
  stable/9/sys/dev/ixgbe/   (props changed)
  stable/9/sys/fs/   (props changed)
  stable/9/sys/fs/ntfs/   (props changed)
  stable/9/sys/modules/   (props changed)

Modified: stable/9/sys/boot/sparc64/loader/main.c
==============================================================================
--- stable/9/sys/boot/sparc64/loader/main.c	Fri May 25 14:54:18 2012	(r235996)
+++ stable/9/sys/boot/sparc64/loader/main.c	Fri May 25 14:57:01 2012	(r235997)
@@ -800,6 +800,18 @@ main(int (*openfirm)(void *))
 	return (1);
 }
 
+COMMAND_SET(heap, "heap", "show heap usage", command_heap);
+
+static int
+command_heap(int argc, char *argv[])
+{
+
+	mallocstats();
+	printf("heap base at %p, top at %p, upper limit at %p\n", heapva,
+	    sbrk(0), heapva + HEAPSZ);
+	return(CMD_OK);
+}
+
 COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
 
 static int
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 15 dfilter service freebsd_committer freebsd_triage 2012-05-25 15:57:25 UTC
Author: marius
Date: Fri May 25 14:57:02 2012
New Revision: 235998
URL: http://svn.freebsd.org/changeset/base/235998

Log:
  MFC: r234897
  
  Add a command for showing the heap usage.
  
  PR:		165025
  Submitted by:	Gavin Mu

Modified:
  stable/8/sys/boot/sparc64/loader/main.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/boot/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/e1000/   (props changed)

Modified: stable/8/sys/boot/sparc64/loader/main.c
==============================================================================
--- stable/8/sys/boot/sparc64/loader/main.c	Fri May 25 14:57:01 2012	(r235997)
+++ stable/8/sys/boot/sparc64/loader/main.c	Fri May 25 14:57:02 2012	(r235998)
@@ -915,6 +915,18 @@ main(int (*openfirm)(void *))
 	return (1);
 }
 
+COMMAND_SET(heap, "heap", "show heap usage", command_heap);
+
+static int
+command_heap(int argc, char *argv[])
+{
+
+	mallocstats();
+	printf("heap base at %p, top at %p, upper limit at %p\n", heapva,
+	    sbrk(0), heapva + HEAPSZ);
+	return(CMD_OK);
+}
+
 COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
 
 static int
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 16 dfilter service freebsd_committer freebsd_triage 2012-05-26 09:54:37 UTC
Author: marius
Date: Sat May 26 08:54:26 2012
New Revision: 236076
URL: http://svn.freebsd.org/changeset/base/236076

Log:
  MFC: r234898, r235207
  
  Add initial support for booting from ZFS on sparc64. At least on Sun Fire
  V100, the firmware is known to be broken and not allowing to simultaneously
  open disk devices, causing attempts to boot from a mirror or RAIDZ to cause
  a crash. This will be worked around later. The firmwares of newer sun4u models
  don't seem to exhibit this problem though.
  
  PR:             165025
  Submitted by:   Gavin Mu

Added:
  stable/9/sys/boot/sparc64/zfsboot/
     - copied from r234898, head/sys/boot/sparc64/zfsboot/
  stable/9/sys/boot/sparc64/zfsloader/
     - copied from r234898, head/sys/boot/sparc64/zfsloader/
Modified:
  stable/9/sys/boot/ofw/libofw/devicename.c
  stable/9/sys/boot/sparc64/Makefile
  stable/9/sys/boot/sparc64/boot1/Makefile
  stable/9/sys/boot/sparc64/boot1/boot1.c
  stable/9/sys/boot/sparc64/loader/Makefile
  stable/9/sys/boot/sparc64/loader/main.c
  stable/9/sys/boot/sparc64/zfsboot/Makefile
  stable/9/sys/boot/zfs/zfs.c
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/amd64/include/xen/   (props changed)
  stable/9/sys/boot/   (props changed)
  stable/9/sys/boot/i386/efi/   (props changed)
  stable/9/sys/boot/ia64/efi/   (props changed)
  stable/9/sys/boot/ia64/ski/   (props changed)
  stable/9/sys/boot/powerpc/boot1.chrp/   (props changed)
  stable/9/sys/boot/powerpc/ofw/   (props changed)
  stable/9/sys/cddl/contrib/opensolaris/   (props changed)
  stable/9/sys/conf/   (props changed)
  stable/9/sys/contrib/dev/acpica/   (props changed)
  stable/9/sys/contrib/octeon-sdk/   (props changed)
  stable/9/sys/contrib/pf/   (props changed)
  stable/9/sys/contrib/x86emu/   (props changed)
  stable/9/sys/dev/   (props changed)
  stable/9/sys/dev/e1000/   (props changed)
  stable/9/sys/dev/ixgbe/   (props changed)
  stable/9/sys/fs/   (props changed)
  stable/9/sys/fs/ntfs/   (props changed)
  stable/9/sys/modules/   (props changed)

Modified: stable/9/sys/boot/ofw/libofw/devicename.c
==============================================================================
--- stable/9/sys/boot/ofw/libofw/devicename.c	Sat May 26 08:44:50 2012	(r236075)
+++ stable/9/sys/boot/ofw/libofw/devicename.c	Sat May 26 08:54:26 2012	(r236076)
@@ -28,6 +28,8 @@
 __FBSDID("$FreeBSD$");
 
 #include <stand.h>
+
+#include "bootstrap.h"
 #include "libofw.h"
 
 static int ofw_parsedev(struct ofw_devdesc **, const char *, const char **);
@@ -76,6 +78,7 @@ ofw_parsedev(struct ofw_devdesc **dev, c
     phandle_t		handle;
     const char		*p;
     const char		*s;
+    char		*ep;
     char		name[256];
     char		type[64];
     int			len;
@@ -87,9 +90,10 @@ ofw_parsedev(struct ofw_devdesc **dev, c
 	len = s - devspec;
 	bcopy(devspec, name, len);
 	name[len] = '\0';
-	if ((handle = OF_finddevice(name)) == -1)
-	    break;
-	if (OF_getprop(handle, "device_type", type, sizeof(type)) == -1)
+	if ((handle = OF_finddevice(name)) == -1) {
+	    bcopy(name, type, len);
+	    type[len] = '\0';
+	} else if (OF_getprop(handle, "device_type", type, sizeof(type)) == -1)
 	    continue;
 	for (i = 0; (dv = devsw[i]) != NULL; i++) {
 	    if (strncmp(dv->dv_name, type, strlen(dv->dv_name)) == 0)
@@ -109,6 +113,18 @@ found:
     strcpy(idev->d_path, name);
     idev->d_dev = dv;
     idev->d_type = dv->dv_type;
+    if (idev->d_type == DEVT_ZFS) {
+	idev->d_unit = 0;
+	p = name + strlen(dv->dv_name);
+	if (*p && (*p != ':')) {
+	    idev->d_unit = strtol(p, &ep, 0);
+	    if (ep == p) {
+		free(idev);
+		return (EUNIT);
+	    }
+	}
+    }
+
     if (dev == NULL) {
 	free(idev);
     } else {

Modified: stable/9/sys/boot/sparc64/Makefile
==============================================================================
--- stable/9/sys/boot/sparc64/Makefile	Sat May 26 08:44:50 2012	(r236075)
+++ stable/9/sys/boot/sparc64/Makefile	Sat May 26 08:54:26 2012	(r236076)
@@ -1,5 +1,5 @@
 # $FreeBSD$
 
-SUBDIR=	boot1 loader
+SUBDIR=	boot1 loader zfsboot zfsloader
 
 .include <bsd.subdir.mk>

Modified: stable/9/sys/boot/sparc64/boot1/Makefile
==============================================================================
--- stable/9/sys/boot/sparc64/boot1/Makefile	Sat May 26 08:44:50 2012	(r236075)
+++ stable/9/sys/boot/sparc64/boot1/Makefile	Sat May 26 08:54:26 2012	(r236076)
@@ -3,22 +3,23 @@
 PROG=	boot1.elf
 INTERNALPROG=
 NO_MAN=
-FILES=	boot1
+FILES?=	boot1
 SRCS=	_start.s boot1.c
+CLEANFILES=${FILES} boot1.aout
 
 BOOTBLOCKBASE= 0x4000
 
-CFLAGS=	-mcmodel=medlow -Os -I${.CURDIR}/../../common
+CFLAGS+=-mcmodel=medlow -Os -I${.CURDIR}/../../common
 LDFLAGS=-Ttext ${BOOTBLOCKBASE} -Wl,-N
 
 # Construct boot1. sunlabel expects it to contain zeroed-out space for the
 # label, and to be of the correct size.
-boot1: boot1.aout
+${FILES}: boot1.aout
+	@set -- `ls -l boot1.aout`; x=$$((7680-$$5)); \
+	    echo "$$x bytes available"; test $$x -ge 0
 	dd if=/dev/zero of=${.TARGET} bs=512 count=16
 	dd if=boot1.aout of=${.TARGET} bs=512 oseek=1 conv=notrunc
 
-CLEANFILES= boot1.aout
-
 boot1.aout: boot1.elf
 	elf2aout -o ${.TARGET} ${.ALLSRC}
 

Modified: stable/9/sys/boot/sparc64/boot1/boot1.c
==============================================================================
--- stable/9/sys/boot/sparc64/boot1/boot1.c	Sat May 26 08:44:50 2012	(r236075)
+++ stable/9/sys/boot/sparc64/boot1/boot1.c	Sat May 26 08:54:26 2012	(r236076)
@@ -20,11 +20,13 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/dirent.h>
+
 #include <machine/elf.h>
 #include <machine/stdarg.h>
 
-#define _PATH_LOADER	"/boot/loader"
-#define _PATH_KERNEL	"/boot/kernel/kernel"
+#define	_PATH_LOADER	"/boot/loader"
+#define	_PATH_KERNEL	"/boot/kernel/kernel"
+#define	READ_BUF_SIZE	8192
 
 typedef int putc_func_t(char c, void *arg);
 typedef int32_t ofwh_t;
@@ -45,17 +47,21 @@ static ofwh_t bootdev;
 static uint32_t fs_off;
 
 int main(int ac, char **av);
-
 static void exit(int) __dead2;
-static void load(const char *);
-static int dskread(void *, u_int64_t, int);
-
 static void usage(void);
 
+#ifdef ZFSBOOT
+static void loadzfs(void);
+static int zbread(char *buf, off_t off, size_t bytes);
+#else
+static void load(const char *);
+#endif
+
 static void bcopy(const void *src, void *dst, size_t len);
 static void bzero(void *b, size_t len);
 
 static int mount(const char *device);
+static int dskread(void *buf, u_int64_t lba, int nblk);
 
 static void panic(const char *fmt, ...) __dead2;
 static int printf(const char *fmt, ...);
@@ -312,8 +318,6 @@ strcmp(const char *s1, const char *s2)
 	return ((u_char)*s1 - (u_char)*s2);
 }
 
-#include "ufsread.c"
-
 int
 main(int ac, char **av)
 {
@@ -335,14 +339,22 @@ main(int ac, char **av)
 		}
 	}
 
-	printf(" \n>> FreeBSD/sparc64 boot block\n"
-	"   Boot path:   %s\n"
-	"   Boot loader: %s\n", bootpath, path);
+#ifdef ZFSBOOT
+	printf(" \n>> FreeBSD/sparc64 ZFS boot block\n    Boot path:   %s\n",
+	    bootpath);
+#else
+	printf(" \n>> FreeBSD/sparc64 boot block\n    Boot path:   %s\n"
+	    "   Boot loader: %s\n", "", bootpath, path);
+#endif
 
 	if (mount(bootpath) == -1)
 		panic("mount");
 
+#ifdef ZFSBOOT
+	loadzfs();
+#else
 	load(path);
+#endif
 	return (1);
 }
 
@@ -361,24 +373,86 @@ exit(int code)
 	ofw_exit();
 }
 
-static struct dmadat __dmadat;
+#ifdef ZFSBOOT
+
+#define	VDEV_BOOT_OFFSET	(2 * 256 * 1024)
+static char zbuf[READ_BUF_SIZE];
 
 static int
-mount(const char *device)
+zbread(char *buf, off_t off, size_t bytes)
 {
+	size_t len;
+	off_t poff;
+	off_t soff;
+	char *p;
+	unsigned int nb;
+	unsigned int lb;
 
-	dmadat = &__dmadat;
-	if ((bootdev = ofw_open(device)) == -1) {
-		printf("mount: can't open device\n");
-		return (-1);
+	p = buf;
+	soff = VDEV_BOOT_OFFSET + off;
+	lb = (soff + bytes + DEV_BSIZE - 1) / DEV_BSIZE;
+	poff = soff;
+	while (poff < soff + bytes) {
+		nb = lb - poff / DEV_BSIZE;
+		if (nb > READ_BUF_SIZE / DEV_BSIZE)
+			nb = READ_BUF_SIZE / DEV_BSIZE;
+		if (dskread(zbuf, poff / DEV_BSIZE, nb))
+			break;
+		if ((poff / DEV_BSIZE + nb) * DEV_BSIZE > soff + bytes)
+			len = soff + bytes - poff;
+		else
+			len = (poff / DEV_BSIZE + nb) * DEV_BSIZE - poff;
+		memcpy(p, zbuf + poff % DEV_BSIZE, len);
+		p += len;
+		poff += len;
 	}
-	if (fsread(0, NULL, 0)) {
-		printf("mount: can't read superblock\n");
-		return (-1);
+	return (poff - soff);
+}
+
+static void
+loadzfs(void)
+{
+	Elf64_Ehdr eh;
+	Elf64_Phdr ph;
+	caddr_t p;
+	ino_t ino;
+	int i;
+
+	if (zbread((char *)&eh, 0, sizeof(eh)) != sizeof(eh)) {
+		printf("Can't read elf header\n");
+		return;
 	}
-	return (0);
+	if (!IS_ELF(eh)) {
+		printf("Not an ELF file\n");
+		return;
+	}
+	for (i = 0; i < eh.e_phnum; i++) {
+		fs_off = eh.e_phoff + i * eh.e_phentsize;
+		if (zbread((char *)&ph, fs_off, sizeof(ph)) != sizeof(ph)) {
+			printf("Can't read program header %d\n", i);
+			return;
+		}
+		if (ph.p_type != PT_LOAD)
+			continue;
+		fs_off = ph.p_offset;
+		p = (caddr_t)ph.p_vaddr;
+		if (zbread(p, fs_off, ph.p_filesz) != ph.p_filesz) {
+			printf("Can't read content of section %d\n", i);
+			return;
+		}
+		if (ph.p_filesz != ph.p_memsz)
+			bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz);
+	}
+	ofw_close(bootdev);
+	(*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw);
 }
 
+#else
+
+#include "ufsread.c"
+
+static struct dmadat __dmadat;
+
 static void
 load(const char *fname)
 {
@@ -421,6 +495,26 @@ load(const char *fname)
 	(*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw);
 }
 
+#endif /* ZFSBOOT */
+
+static int
+mount(const char *device)
+{
+
+	if ((bootdev = ofw_open(device)) == -1) {
+		printf("mount: can't open device\n");
+		return (-1);
+	}
+#ifndef ZFSBOOT
+	dmadat = &__dmadat;
+	if (fsread(0, NULL, 0)) {
+		printf("mount: can't read superblock\n");
+		return (-1);
+	}
+#endif
+	return (0);
+}
+
 static int
 dskread(void *buf, u_int64_t lba, int nblk)
 {

Modified: stable/9/sys/boot/sparc64/loader/Makefile
==============================================================================
--- stable/9/sys/boot/sparc64/loader/Makefile	Sat May 26 08:44:50 2012	(r236075)
+++ stable/9/sys/boot/sparc64/loader/Makefile	Sat May 26 08:54:26 2012	(r236076)
@@ -3,8 +3,8 @@
 .include <bsd.own.mk>
 MK_SSP=		no
 
-PROG=		loader
-NEWVERSWHAT=	"bootstrap loader" sparc64
+PROG?=		loader
+NEWVERSWHAT?=	"bootstrap loader" sparc64
 INSTALLFLAGS=	-b
 
 # Architecture-specific loader code
@@ -13,12 +13,17 @@ SRCS=		locore.S main.c metadata.c vers.c
 LOADER_DISK_SUPPORT?=	yes
 LOADER_UFS_SUPPORT?=	yes
 LOADER_CD9660_SUPPORT?=	yes
+LOADER_ZFS_SUPPORT?=	no
 LOADER_NET_SUPPORT?=	yes
 LOADER_NFS_SUPPORT?=	yes
 LOADER_TFTP_SUPPORT?=	yes
 LOADER_GZIP_SUPPORT?=	yes
 LOADER_BZIP2_SUPPORT?=	no
+LOADER_DEBUG?=		no
 
+.if ${LOADER_DEBUG} == "yes"
+CFLAGS+=	-DLOADER_DEBUG
+.endif
 .if ${LOADER_DISK_SUPPORT} == "yes"
 CFLAGS+=	-DLOADER_DISK_SUPPORT
 .endif
@@ -28,6 +33,11 @@ CFLAGS+=	-DLOADER_UFS_SUPPORT
 .if ${LOADER_CD9660_SUPPORT} == "yes"
 CFLAGS+=	-DLOADER_CD9660_SUPPORT
 .endif
+.if ${LOADER_ZFS_SUPPORT} == "yes"
+CFLAGS+=	-DLOADER_ZFS_SUPPORT
+CFLAGS+=	-I${.CURDIR}/../../zfs
+CFLAGS+=	-I${.CURDIR}/../../../cddl/boot/zfs
+.endif
 .if ${LOADER_GZIP_SUPPORT} == "yes"
 CFLAGS+=	-DLOADER_GZIP_SUPPORT
 .endif
@@ -47,7 +57,8 @@ CFLAGS+=	-DLOADER_TFTP_SUPPORT
 .if ${MK_FORTH} != "no"
 # Enable BootForth
 BOOT_FORTH=	yes
-CFLAGS+=	-DBOOT_FORTH -I${.CURDIR}/../../ficl -I${.CURDIR}/../../ficl/sparc64
+CFLAGS+=	-DBOOT_FORTH -I${.CURDIR}/../../ficl
+CFLAGS+=	-I${.CURDIR}/../../ficl/sparc64
 LIBFICL=	${.OBJDIR}/../../ficl/libficl.a
 .endif
 
@@ -75,8 +86,9 @@ CFLAGS+=	-I${.CURDIR}/../../../../lib/li
 DPADD=		${LIBFICL} ${LIBOFW} ${LIBSTAND}
 LDADD=		${LIBFICL} ${LIBOFW} -lstand
 
-vers.c:	${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version
-	sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT}
+vers.c:	${.CURDIR}/../../common/newvers.sh ${.CURDIR}/../loader/version
+	sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/../loader/version \
+	    ${NEWVERSWHAT}
 
 loader.help: help.common help.sparc64
 	cat ${.ALLSRC} | \

Modified: stable/9/sys/boot/sparc64/loader/main.c
==============================================================================
--- stable/9/sys/boot/sparc64/loader/main.c	Sat May 26 08:44:50 2012	(r236075)
+++ stable/9/sys/boot/sparc64/loader/main.c	Sat May 26 08:54:26 2012	(r236076)
@@ -51,6 +51,9 @@ __FBSDID("$FreeBSD$");
 #include <sys/linker.h>
 #include <sys/queue.h>
 #include <sys/types.h>
+#ifdef LOADER_ZFS_SUPPORT
+#include <sys/vtoc.h>
+#endif
 
 #include <vm/vm.h>
 #include <machine/asi.h>
@@ -143,6 +146,11 @@ static vm_offset_t heapva;
 
 static phandle_t root;
 
+#ifdef LOADER_ZFS_SUPPORT
+static int zfs_dev_init(void);
+#include "zfs.c"
+#endif
+
 /*
  * Machine dependent structures that the machine independent
  * loader part uses.
@@ -154,6 +162,9 @@ struct devsw *devsw[] = {
 #ifdef LOADER_NET_SUPPORT
 	&netdev,
 #endif
+#ifdef LOADER_ZFS_SUPPORT
+	&zfs_dev,
+#endif
 	0
 };
 struct arch_switch archsw;
@@ -166,6 +177,7 @@ struct file_format *file_formats[] = {
 	&sparc64_elf,
 	0
 };
+
 struct fs_ops *file_system[] = {
 #ifdef LOADER_UFS_SUPPORT
 	&ufs_fsops,
@@ -173,6 +185,9 @@ struct fs_ops *file_system[] = {
 #ifdef LOADER_CD9660_SUPPORT
 	&cd9660_fsops,
 #endif
+#ifdef LOADER_ZFS_SUPPORT
+	&zfs_fsops,
+#endif
 #ifdef LOADER_ZIP_SUPPORT
 	&zipfs_fsops,
 #endif
@@ -721,6 +736,82 @@ tlb_init_sun4u(void)
 		panic("%s: can't allocate TLB store", __func__);
 }
 
+#ifdef LOADER_ZFS_SUPPORT
+
+static int
+zfs_dev_init(void)
+{
+	struct vtoc8 vtoc;
+	char devname[512];
+	spa_t *spa;
+	vdev_t *vdev;
+	uint64_t guid;
+	int fd, part, unit;
+
+	zfs_init();
+
+	guid = 0;
+	/* Get the GUID of the ZFS pool on the boot device. */
+	fd = open(getenv("currdev"), O_RDONLY);
+	if (fd != -1) {
+		if (vdev_probe(vdev_read, (void *)(uintptr_t) fd, &spa) == 0)
+			guid = spa->spa_guid;
+		close(fd);
+	}
+
+	/* Clean up the environment to let ZFS work. */
+	while ((vdev = STAILQ_FIRST(&zfs_vdevs)) != NULL) {
+		STAILQ_REMOVE_HEAD(&zfs_vdevs, v_alllink);
+		free(vdev);
+	}
+	while ((spa = STAILQ_FIRST(&zfs_pools)) != NULL) {
+		STAILQ_REMOVE_HEAD(&zfs_pools, spa_link);
+		free(spa);
+	}
+
+	for (unit = 0; unit < MAXBDDEV; unit++) {
+		/* Find freebsd-zfs slices in the VTOC. */
+		sprintf(devname, "disk%d:", unit);
+		fd = open(devname, O_RDONLY);
+		if (fd == -1)
+			continue;
+		lseek(fd, 0, SEEK_SET);
+		if (read(fd, &vtoc, sizeof(vtoc)) != sizeof(vtoc)) {
+			close(fd);
+			continue;
+		}
+		close(fd);
+
+		for (part = 0; part < 8; part++) {
+			if (part == 2 || vtoc.part[part].tag !=
+			     VTOC_TAG_FREEBSD_ZFS)
+				continue;
+			sprintf(devname, "disk%d:%c", unit, part + 'a');
+			fd = open(devname, O_RDONLY);
+			if (fd == -1)
+				break;
+
+			if (vdev_probe(vdev_read, (void*)(uintptr_t) fd, 0))
+				close(fd);
+		}
+	}
+
+	if (guid != 0) {
+		unit = zfs_guid_to_unit(guid);
+		if (unit >= 0) {
+			/* Update the environment for ZFS. */
+			sprintf(devname, "zfs%d", unit);
+			env_setenv("currdev", EV_VOLATILE, devname,
+			   ofw_setcurrdev, env_nounset);
+			env_setenv("loaddev", EV_VOLATILE, devname,
+			   env_noset, env_nounset);
+		}
+	}
+	return (0);
+}
+
+#endif /* LOADER_ZFS_SUPPORT */
+
 int
 main(int (*openfirm)(void *))
 {
@@ -756,14 +847,6 @@ main(int (*openfirm)(void *))
 	mmu_ops->tlb_init();
 
 	/*
-	 * Initialize devices.
-	 */
-	for (dp = devsw; *dp != 0; dp++) {
-		if ((*dp)->dv_init != 0)
-			(*dp)->dv_init();
-	}
-
-	/*
 	 * Set up the current device.
 	 */
 	OF_getprop(chosen, "bootpath", bootpath, sizeof(bootpath));
@@ -780,7 +863,8 @@ main(int (*openfirm)(void *))
 	 * needs to be altered.
 	 */
 	if (bootpath[strlen(bootpath) - 2] == ':' &&
-	    bootpath[strlen(bootpath) - 1] == 'f') {
+	    bootpath[strlen(bootpath) - 1] == 'f' &&
+	    strstr(bootpath, "cdrom")) {
 		bootpath[strlen(bootpath) - 1] = 'a';
 		printf("Boot path set to %s\n", bootpath);
 	}
@@ -790,6 +874,13 @@ main(int (*openfirm)(void *))
 	env_setenv("loaddev", EV_VOLATILE, bootpath,
 	    env_noset, env_nounset);
 
+	/*
+	 * Initialize devices.
+	 */
+	for (dp = devsw; *dp != 0; dp++)
+		if ((*dp)->dv_init != 0)
+			(*dp)->dv_init();
+
 	printf("\n");
 	printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
 	printf("(%s, %s)\n", bootprog_maker, bootprog_date);

Modified: stable/9/sys/boot/sparc64/zfsboot/Makefile
==============================================================================
--- head/sys/boot/sparc64/zfsboot/Makefile	Tue May  1 17:16:01 2012	(r234898)
+++ stable/9/sys/boot/sparc64/zfsboot/Makefile	Sat May 26 08:54:26 2012	(r236076)
@@ -5,9 +5,5 @@
 PROGNAME=	zfsboot
 CFLAGS+=	-DZFSBOOT
 FILES=		zfsboot
-CLEANFILES+=	zfsboot
-
-zfsboot: boot1
-	ln -s ${.ALLSRC} ${.TARGET}
 
 .include "${.CURDIR}/../boot1/Makefile"

Modified: stable/9/sys/boot/zfs/zfs.c
==============================================================================
--- stable/9/sys/boot/zfs/zfs.c	Sat May 26 08:44:50 2012	(r236075)
+++ stable/9/sys/boot/zfs/zfs.c	Sat May 26 08:54:26 2012	(r236076)
@@ -399,6 +399,7 @@ zfs_guid_to_unit(uint64_t guid)
 	return (-1);
 }
 
+#if defined(__amd64__) || defined(__i386__)
 static int
 zfs_dev_init(void) 
 {
@@ -441,6 +442,7 @@ zfs_dev_init(void) 
 
 	return (0);
 }
+#endif
 
 /*
  * Print information about ZFS pools
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 17 dfilter service freebsd_committer freebsd_triage 2012-05-26 09:54:54 UTC
Author: marius
Date: Sat May 26 08:54:44 2012
New Revision: 236077
URL: http://svn.freebsd.org/changeset/base/236077

Log:
  MFC: r234898, r235207
  
  Add initial support for booting from ZFS on sparc64. At least on Sun Fire
  V100, the firmware is known to be broken and not allowing to simultaneously
  open disk devices, causing attempts to boot from a mirror or RAIDZ to cause
  a crash. This will be worked around later. The firmwares of newer sun4u models
  don't seem to exhibit this problem though.
  
  PR:             165025
  Submitted by:   Gavin Mu

Added:
  stable/8/sys/boot/sparc64/zfsboot/
     - copied from r234898, head/sys/boot/sparc64/zfsboot/
  stable/8/sys/boot/sparc64/zfsloader/
     - copied from r234898, head/sys/boot/sparc64/zfsloader/
Modified:
  stable/8/sys/boot/ofw/libofw/devicename.c
  stable/8/sys/boot/sparc64/Makefile
  stable/8/sys/boot/sparc64/boot1/Makefile
  stable/8/sys/boot/sparc64/boot1/boot1.c
  stable/8/sys/boot/sparc64/loader/Makefile
  stable/8/sys/boot/sparc64/loader/main.c
  stable/8/sys/boot/sparc64/zfsboot/Makefile
  stable/8/sys/boot/zfs/zfs.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/boot/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/e1000/   (props changed)

Modified: stable/8/sys/boot/ofw/libofw/devicename.c
==============================================================================
--- stable/8/sys/boot/ofw/libofw/devicename.c	Sat May 26 08:54:26 2012	(r236076)
+++ stable/8/sys/boot/ofw/libofw/devicename.c	Sat May 26 08:54:44 2012	(r236077)
@@ -28,6 +28,8 @@
 __FBSDID("$FreeBSD$");
 
 #include <stand.h>
+
+#include "bootstrap.h"
 #include "libofw.h"
 
 static int ofw_parsedev(struct ofw_devdesc **, const char *, const char **);
@@ -76,6 +78,7 @@ ofw_parsedev(struct ofw_devdesc **dev, c
     phandle_t		handle;
     const char		*p;
     const char		*s;
+    char		*ep;
     char		name[256];
     char		type[64];
     int			len;
@@ -87,9 +90,10 @@ ofw_parsedev(struct ofw_devdesc **dev, c
 	len = s - devspec;
 	bcopy(devspec, name, len);
 	name[len] = '\0';
-	if ((handle = OF_finddevice(name)) == -1)
-	    break;
-	if (OF_getprop(handle, "device_type", type, sizeof(type)) == -1)
+	if ((handle = OF_finddevice(name)) == -1) {
+	    bcopy(name, type, len);
+	    type[len] = '\0';
+	} else if (OF_getprop(handle, "device_type", type, sizeof(type)) == -1)
 	    continue;
 	for (i = 0; (dv = devsw[i]) != NULL; i++) {
 	    if (strncmp(dv->dv_name, type, strlen(dv->dv_name)) == 0)
@@ -109,6 +113,18 @@ found:
     strcpy(idev->d_path, name);
     idev->d_dev = dv;
     idev->d_type = dv->dv_type;
+    if (idev->d_type == DEVT_ZFS) {
+	idev->d_unit = 0;
+	p = name + strlen(dv->dv_name);
+	if (*p && (*p != ':')) {
+	    idev->d_unit = strtol(p, &ep, 0);
+	    if (ep == p) {
+		free(idev);
+		return (EUNIT);
+	    }
+	}
+    }
+
     if (dev == NULL) {
 	free(idev);
     } else {

Modified: stable/8/sys/boot/sparc64/Makefile
==============================================================================
--- stable/8/sys/boot/sparc64/Makefile	Sat May 26 08:54:26 2012	(r236076)
+++ stable/8/sys/boot/sparc64/Makefile	Sat May 26 08:54:44 2012	(r236077)
@@ -1,5 +1,5 @@
 # $FreeBSD$
 
-SUBDIR=	boot1 loader
+SUBDIR=	boot1 loader zfsboot zfsloader
 
 .include <bsd.subdir.mk>

Modified: stable/8/sys/boot/sparc64/boot1/Makefile
==============================================================================
--- stable/8/sys/boot/sparc64/boot1/Makefile	Sat May 26 08:54:26 2012	(r236076)
+++ stable/8/sys/boot/sparc64/boot1/Makefile	Sat May 26 08:54:44 2012	(r236077)
@@ -3,22 +3,23 @@
 PROG=	boot1.elf
 INTERNALPROG=
 NO_MAN=
-FILES=	boot1
+FILES?=	boot1
 SRCS=	_start.s boot1.c
+CLEANFILES=${FILES} boot1.aout
 
 BOOTBLOCKBASE= 0x4000
 
-CFLAGS=	-mcmodel=medlow -Os -I${.CURDIR}/../../common
+CFLAGS+=-mcmodel=medlow -Os -I${.CURDIR}/../../common
 LDFLAGS=-N -Ttext ${BOOTBLOCKBASE}
 
 # Construct boot1. sunlabel expects it to contain zeroed-out space for the
 # label, and to be of the correct size.
-boot1: boot1.aout
+${FILES}: boot1.aout
+	@set -- `ls -l boot1.aout`; x=$$((7680-$$5)); \
+	    echo "$$x bytes available"; test $$x -ge 0
 	dd if=/dev/zero of=${.TARGET} bs=512 count=16
 	dd if=boot1.aout of=${.TARGET} bs=512 oseek=1 conv=notrunc
 
-CLEANFILES= boot1.aout
-
 boot1.aout: boot1.elf
 	elf2aout -o ${.TARGET} ${.ALLSRC}
 

Modified: stable/8/sys/boot/sparc64/boot1/boot1.c
==============================================================================
--- stable/8/sys/boot/sparc64/boot1/boot1.c	Sat May 26 08:54:26 2012	(r236076)
+++ stable/8/sys/boot/sparc64/boot1/boot1.c	Sat May 26 08:54:44 2012	(r236077)
@@ -20,11 +20,13 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/dirent.h>
+
 #include <machine/elf.h>
 #include <machine/stdarg.h>
 
-#define _PATH_LOADER	"/boot/loader"
-#define _PATH_KERNEL	"/boot/kernel/kernel"
+#define	_PATH_LOADER	"/boot/loader"
+#define	_PATH_KERNEL	"/boot/kernel/kernel"
+#define	READ_BUF_SIZE	8192
 
 typedef int putc_func_t(char c, void *arg);
 typedef int32_t ofwh_t;
@@ -45,17 +47,21 @@ static ofwh_t bootdev;
 static uint32_t fs_off;
 
 int main(int ac, char **av);
-
 static void exit(int) __dead2;
-static void load(const char *);
-static int dskread(void *, u_int64_t, int);
-
 static void usage(void);
 
+#ifdef ZFSBOOT
+static void loadzfs(void);
+static int zbread(char *buf, off_t off, size_t bytes);
+#else
+static void load(const char *);
+#endif
+
 static void bcopy(const void *src, void *dst, size_t len);
 static void bzero(void *b, size_t len);
 
 static int mount(const char *device);
+static int dskread(void *buf, u_int64_t lba, int nblk);
 
 static void panic(const char *fmt, ...) __dead2;
 static int printf(const char *fmt, ...);
@@ -312,8 +318,6 @@ strcmp(const char *s1, const char *s2)
 	return ((u_char)*s1 - (u_char)*s2);
 }
 
-#include "ufsread.c"
-
 int
 main(int ac, char **av)
 {
@@ -335,14 +339,22 @@ main(int ac, char **av)
 		}
 	}
 
-	printf(" \n>> FreeBSD/sparc64 boot block\n"
-	"   Boot path:   %s\n"
-	"   Boot loader: %s\n", bootpath, path);
+#ifdef ZFSBOOT
+	printf(" \n>> FreeBSD/sparc64 ZFS boot block\n    Boot path:   %s\n",
+	    bootpath);
+#else
+	printf(" \n>> FreeBSD/sparc64 boot block\n    Boot path:   %s\n"
+	    "   Boot loader: %s\n", "", bootpath, path);
+#endif
 
 	if (mount(bootpath) == -1)
 		panic("mount");
 
+#ifdef ZFSBOOT
+	loadzfs();
+#else
 	load(path);
+#endif
 	return (1);
 }
 
@@ -361,24 +373,86 @@ exit(int code)
 	ofw_exit();
 }
 
-static struct dmadat __dmadat;
+#ifdef ZFSBOOT
+
+#define	VDEV_BOOT_OFFSET	(2 * 256 * 1024)
+static char zbuf[READ_BUF_SIZE];
 
 static int
-mount(const char *device)
+zbread(char *buf, off_t off, size_t bytes)
 {
+	size_t len;
+	off_t poff;
+	off_t soff;
+	char *p;
+	unsigned int nb;
+	unsigned int lb;
 
-	dmadat = &__dmadat;
-	if ((bootdev = ofw_open(device)) == -1) {
-		printf("mount: can't open device\n");
-		return (-1);
+	p = buf;
+	soff = VDEV_BOOT_OFFSET + off;
+	lb = (soff + bytes + DEV_BSIZE - 1) / DEV_BSIZE;
+	poff = soff;
+	while (poff < soff + bytes) {
+		nb = lb - poff / DEV_BSIZE;
+		if (nb > READ_BUF_SIZE / DEV_BSIZE)
+			nb = READ_BUF_SIZE / DEV_BSIZE;
+		if (dskread(zbuf, poff / DEV_BSIZE, nb))
+			break;
+		if ((poff / DEV_BSIZE + nb) * DEV_BSIZE > soff + bytes)
+			len = soff + bytes - poff;
+		else
+			len = (poff / DEV_BSIZE + nb) * DEV_BSIZE - poff;
+		memcpy(p, zbuf + poff % DEV_BSIZE, len);
+		p += len;
+		poff += len;
 	}
-	if (fsread(0, NULL, 0)) {
-		printf("mount: can't read superblock\n");
-		return (-1);
+	return (poff - soff);
+}
+
+static void
+loadzfs(void)
+{
+	Elf64_Ehdr eh;
+	Elf64_Phdr ph;
+	caddr_t p;
+	ino_t ino;
+	int i;
+
+	if (zbread((char *)&eh, 0, sizeof(eh)) != sizeof(eh)) {
+		printf("Can't read elf header\n");
+		return;
 	}
-	return (0);
+	if (!IS_ELF(eh)) {
+		printf("Not an ELF file\n");
+		return;
+	}
+	for (i = 0; i < eh.e_phnum; i++) {
+		fs_off = eh.e_phoff + i * eh.e_phentsize;
+		if (zbread((char *)&ph, fs_off, sizeof(ph)) != sizeof(ph)) {
+			printf("Can't read program header %d\n", i);
+			return;
+		}
+		if (ph.p_type != PT_LOAD)
+			continue;
+		fs_off = ph.p_offset;
+		p = (caddr_t)ph.p_vaddr;
+		if (zbread(p, fs_off, ph.p_filesz) != ph.p_filesz) {
+			printf("Can't read content of section %d\n", i);
+			return;
+		}
+		if (ph.p_filesz != ph.p_memsz)
+			bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz);
+	}
+	ofw_close(bootdev);
+	(*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw);
 }
 
+#else
+
+#include "ufsread.c"
+
+static struct dmadat __dmadat;
+
 static void
 load(const char *fname)
 {
@@ -421,6 +495,26 @@ load(const char *fname)
 	(*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw);
 }
 
+#endif /* ZFSBOOT */
+
+static int
+mount(const char *device)
+{
+
+	if ((bootdev = ofw_open(device)) == -1) {
+		printf("mount: can't open device\n");
+		return (-1);
+	}
+#ifndef ZFSBOOT
+	dmadat = &__dmadat;
+	if (fsread(0, NULL, 0)) {
+		printf("mount: can't read superblock\n");
+		return (-1);
+	}
+#endif
+	return (0);
+}
+
 static int
 dskread(void *buf, u_int64_t lba, int nblk)
 {

Modified: stable/8/sys/boot/sparc64/loader/Makefile
==============================================================================
--- stable/8/sys/boot/sparc64/loader/Makefile	Sat May 26 08:54:26 2012	(r236076)
+++ stable/8/sys/boot/sparc64/loader/Makefile	Sat May 26 08:54:44 2012	(r236077)
@@ -3,8 +3,8 @@
 .include <bsd.own.mk>
 MK_SSP=		no
 
-PROG=		loader
-NEWVERSWHAT=	"bootstrap loader" sparc64
+PROG?=		loader
+NEWVERSWHAT?=	"bootstrap loader" sparc64
 INSTALLFLAGS=	-b
 
 # Architecture-specific loader code
@@ -13,12 +13,17 @@ SRCS=		locore.S main.c metadata.c vers.c
 LOADER_DISK_SUPPORT?=	yes
 LOADER_UFS_SUPPORT?=	yes
 LOADER_CD9660_SUPPORT?=	yes
+LOADER_ZFS_SUPPORT?=	no
 LOADER_NET_SUPPORT?=	yes
 LOADER_NFS_SUPPORT?=	yes
 LOADER_TFTP_SUPPORT?=	yes
 LOADER_GZIP_SUPPORT?=	yes
 LOADER_BZIP2_SUPPORT?=	no
+LOADER_DEBUG?=		no
 
+.if ${LOADER_DEBUG} == "yes"
+CFLAGS+=	-DLOADER_DEBUG
+.endif
 .if ${LOADER_DISK_SUPPORT} == "yes"
 CFLAGS+=	-DLOADER_DISK_SUPPORT
 .endif
@@ -28,6 +33,11 @@ CFLAGS+=	-DLOADER_UFS_SUPPORT
 .if ${LOADER_CD9660_SUPPORT} == "yes"
 CFLAGS+=	-DLOADER_CD9660_SUPPORT
 .endif
+.if ${LOADER_ZFS_SUPPORT} == "yes"
+CFLAGS+=	-DLOADER_ZFS_SUPPORT
+CFLAGS+=	-I${.CURDIR}/../../zfs
+CFLAGS+=	-I${.CURDIR}/../../../cddl/boot/zfs
+.endif
 .if ${LOADER_GZIP_SUPPORT} == "yes"
 CFLAGS+=	-DLOADER_GZIP_SUPPORT
 .endif
@@ -47,7 +57,8 @@ CFLAGS+=	-DLOADER_TFTP_SUPPORT
 .if ${MK_FORTH} != "no"
 # Enable BootForth
 BOOT_FORTH=	yes
-CFLAGS+=	-DBOOT_FORTH -I${.CURDIR}/../../ficl -I${.CURDIR}/../../ficl/sparc64
+CFLAGS+=	-DBOOT_FORTH -I${.CURDIR}/../../ficl
+CFLAGS+=	-I${.CURDIR}/../../ficl/sparc64
 LIBFICL=	${.OBJDIR}/../../ficl/libficl.a
 .endif
 
@@ -75,8 +86,9 @@ CFLAGS+=	-I${.CURDIR}/../../../../lib/li
 DPADD=		${LIBFICL} ${LIBOFW} ${LIBSTAND}
 LDADD=		${LIBFICL} ${LIBOFW} -lstand
 
-vers.c:	${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version
-	sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT}
+vers.c:	${.CURDIR}/../../common/newvers.sh ${.CURDIR}/../loader/version
+	sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/../loader/version \
+	    ${NEWVERSWHAT}
 
 loader.help: help.common help.sparc64
 	cat ${.ALLSRC} | \

Modified: stable/8/sys/boot/sparc64/loader/main.c
==============================================================================
--- stable/8/sys/boot/sparc64/loader/main.c	Sat May 26 08:54:26 2012	(r236076)
+++ stable/8/sys/boot/sparc64/loader/main.c	Sat May 26 08:54:44 2012	(r236077)
@@ -51,6 +51,9 @@ __FBSDID("$FreeBSD$");
 #include <sys/linker.h>
 #include <sys/queue.h>
 #include <sys/types.h>
+#ifdef LOADER_ZFS_SUPPORT
+#include <sys/vtoc.h>
+#endif
 
 #include <vm/vm.h>
 #include <machine/asi.h>
@@ -157,6 +160,11 @@ static vm_offset_t heapva;
 
 static phandle_t root;
 
+#ifdef LOADER_ZFS_SUPPORT
+static int zfs_dev_init(void);
+#include "zfs.c"
+#endif
+
 /*
  * Machine dependent structures that the machine independent
  * loader part uses.
@@ -168,6 +176,9 @@ struct devsw *devsw[] = {
 #ifdef LOADER_NET_SUPPORT
 	&netdev,
 #endif
+#ifdef LOADER_ZFS_SUPPORT
+	&zfs_dev,
+#endif
 	0
 };
 struct arch_switch archsw;
@@ -180,6 +191,7 @@ struct file_format *file_formats[] = {
 	&sparc64_elf,
 	0
 };
+
 struct fs_ops *file_system[] = {
 #ifdef LOADER_UFS_SUPPORT
 	&ufs_fsops,
@@ -187,6 +199,9 @@ struct fs_ops *file_system[] = {
 #ifdef LOADER_CD9660_SUPPORT
 	&cd9660_fsops,
 #endif
+#ifdef LOADER_ZFS_SUPPORT
+	&zfs_fsops,
+#endif
 #ifdef LOADER_ZIP_SUPPORT
 	&zipfs_fsops,
 #endif
@@ -828,6 +843,82 @@ tlb_init_sun4v(void)
 	memset(tlb_store, 0xFF, SUN4V_TLB_SLOT_MAX * sizeof(*tlb_store));
 }
 
+#ifdef LOADER_ZFS_SUPPORT
+
+static int
+zfs_dev_init(void)
+{
+	struct vtoc8 vtoc;
+	char devname[512];
+	spa_t *spa;
+	vdev_t *vdev;
+	uint64_t guid;
+	int fd, part, unit;
+
+	zfs_init();
+
+	guid = 0;
+	/* Get the GUID of the ZFS pool on the boot device. */
+	fd = open(getenv("currdev"), O_RDONLY);
+	if (fd != -1) {
+		if (vdev_probe(vdev_read, (void *)(uintptr_t) fd, &spa) == 0)
+			guid = spa->spa_guid;
+		close(fd);
+	}
+
+	/* Clean up the environment to let ZFS work. */
+	while ((vdev = STAILQ_FIRST(&zfs_vdevs)) != NULL) {
+		STAILQ_REMOVE_HEAD(&zfs_vdevs, v_alllink);
+		free(vdev);
+	}
+	while ((spa = STAILQ_FIRST(&zfs_pools)) != NULL) {
+		STAILQ_REMOVE_HEAD(&zfs_pools, spa_link);
+		free(spa);
+	}
+
+	for (unit = 0; unit < MAXBDDEV; unit++) {
+		/* Find freebsd-zfs slices in the VTOC. */
+		sprintf(devname, "disk%d:", unit);
+		fd = open(devname, O_RDONLY);
+		if (fd == -1)
+			continue;
+		lseek(fd, 0, SEEK_SET);
+		if (read(fd, &vtoc, sizeof(vtoc)) != sizeof(vtoc)) {
+			close(fd);
+			continue;
+		}
+		close(fd);
+
+		for (part = 0; part < 8; part++) {
+			if (part == 2 || vtoc.part[part].tag !=
+			     VTOC_TAG_FREEBSD_ZFS)
+				continue;
+			sprintf(devname, "disk%d:%c", unit, part + 'a');
+			fd = open(devname, O_RDONLY);
+			if (fd == -1)
+				break;
+
+			if (vdev_probe(vdev_read, (void*)(uintptr_t) fd, 0))
+				close(fd);
+		}
+	}
+
+	if (guid != 0) {
+		unit = zfs_guid_to_unit(guid);
+		if (unit >= 0) {
+			/* Update the environment for ZFS. */
+			sprintf(devname, "zfs%d", unit);
+			env_setenv("currdev", EV_VOLATILE, devname,
+			   ofw_setcurrdev, env_nounset);
+			env_setenv("loaddev", EV_VOLATILE, devname,
+			   env_noset, env_nounset);
+		}
+	}
+	return (0);
+}
+
+#endif /* LOADER_ZFS_SUPPORT */
+
 int
 main(int (*openfirm)(void *))
 {
@@ -871,14 +962,6 @@ main(int (*openfirm)(void *))
 	mmu_ops->tlb_init();
 
 	/*
-	 * Initialize devices.
-	 */
-	for (dp = devsw; *dp != 0; dp++) {
-		if ((*dp)->dv_init != 0)
-			(*dp)->dv_init();
-	}
-
-	/*
 	 * Set up the current device.
 	 */
 	OF_getprop(chosen, "bootpath", bootpath, sizeof(bootpath));
@@ -895,7 +978,8 @@ main(int (*openfirm)(void *))
 	 * needs to be altered.
 	 */
 	if (bootpath[strlen(bootpath) - 2] == ':' &&
-	    bootpath[strlen(bootpath) - 1] == 'f') {
+	    bootpath[strlen(bootpath) - 1] == 'f' &&
+	    strstr(bootpath, "cdrom")) {
 		bootpath[strlen(bootpath) - 1] = 'a';
 		printf("Boot path set to %s\n", bootpath);
 	}
@@ -905,6 +989,13 @@ main(int (*openfirm)(void *))
 	env_setenv("loaddev", EV_VOLATILE, bootpath,
 	    env_noset, env_nounset);
 
+	/*
+	 * Initialize devices.
+	 */
+	for (dp = devsw; *dp != 0; dp++)
+		if ((*dp)->dv_init != 0)
+			(*dp)->dv_init();
+
 	printf("\n");
 	printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
 	printf("(%s, %s)\n", bootprog_maker, bootprog_date);

Modified: stable/8/sys/boot/sparc64/zfsboot/Makefile
==============================================================================
--- head/sys/boot/sparc64/zfsboot/Makefile	Tue May  1 17:16:01 2012	(r234898)
+++ stable/8/sys/boot/sparc64/zfsboot/Makefile	Sat May 26 08:54:44 2012	(r236077)
@@ -5,9 +5,5 @@
 PROGNAME=	zfsboot
 CFLAGS+=	-DZFSBOOT
 FILES=		zfsboot
-CLEANFILES+=	zfsboot
-
-zfsboot: boot1
-	ln -s ${.ALLSRC} ${.TARGET}
 
 .include "${.CURDIR}/../boot1/Makefile"

Modified: stable/8/sys/boot/zfs/zfs.c
==============================================================================
--- stable/8/sys/boot/zfs/zfs.c	Sat May 26 08:54:26 2012	(r236076)
+++ stable/8/sys/boot/zfs/zfs.c	Sat May 26 08:54:44 2012	(r236077)
@@ -399,6 +399,7 @@ zfs_guid_to_unit(uint64_t guid)
 	return (-1);
 }
 
+#if defined(__amd64__) || defined(__i386__)
 static int
 zfs_dev_init(void) 
 {
@@ -441,6 +442,7 @@ zfs_dev_init(void) 
 
 	return (0);
 }
+#endif
 
 /*
  * Print information about ZFS pools
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 18 dfilter service freebsd_committer freebsd_triage 2012-06-04 21:45:54 UTC
Author: marius
Date: Mon Jun  4 20:45:33 2012
New Revision: 236579
URL: http://svn.freebsd.org/changeset/base/236579

Log:
  The workaround added in r151650 for handling firmwares that don't allow
  a single device to be opened multiple times concurrently unfortunately
  isn't sufficient with ZFS. This is due to the fact, that ZFS may open
  different partitions of a single device simultaneously. So the best we
  can do in this case is to cache the lastly used device path and close
  and open devices in ofwd_strategy() as needed.
  
  PR:		165025
  Submitted by:	Gavin Mu
  MFC after:	1 week

Modified:
  head/sys/boot/ofw/libofw/ofw_disk.c

Modified: head/sys/boot/ofw/libofw/ofw_disk.c
==============================================================================
--- head/sys/boot/ofw/libofw/ofw_disk.c	Mon Jun  4 20:36:11 2012	(r236578)
+++ head/sys/boot/ofw/libofw/ofw_disk.c	Mon Jun  4 20:45:33 2012	(r236579)
@@ -31,7 +31,6 @@ __FBSDID("$FreeBSD$");
  */
 
 #include <sys/param.h>
-#include <sys/queue.h>
 
 #include <netinet/in.h>
 
@@ -43,8 +42,8 @@ __FBSDID("$FreeBSD$");
 #include "libofw.h"
 
 static int	ofwd_init(void);
-static int	ofwd_strategy(void *devdata, int flag, daddr_t dblk, 
-				size_t size, char *buf, size_t *rsize);
+static int	ofwd_strategy(void *devdata, int flag, daddr_t dblk,
+		    size_t size, char *buf, size_t *rsize);
 static int	ofwd_open(struct open_file *f, ...);
 static int	ofwd_close(struct open_file *f);
 static int	ofwd_ioctl(struct open_file *f, u_long cmd, void *data);
@@ -61,120 +60,109 @@ 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_devs);
+/*
+ * We're not guaranteed to be able to open a device more than once and there
+ * is no OFW standard method to determine whether a device is already opened.
+ * Opening a device multiple times simultaneously happens to work with most
+ * OFW block device drivers but triggers a trap with at least the driver for
+ * the on-board controllers of Sun Fire V100 and Ultra 1.  Upper layers and MI
+ * code expect to be able to open a device more than once however.  Given that
+ * different partitions of the same device might be opened at the same time as
+ * done by ZFS, we can't generally just keep track of the opened devices and
+ * reuse the instance handle when asked to open an already opened device.  So
+ * the best we can do is to cache the lastly used device path and close and
+ * open devices in ofwd_strategy() as needed.
+ */
+static struct ofw_devdesc *kdp;
 
 static int
 ofwd_init(void)
 {
 
-	return 0;
+	return (0);
 }
 
 static int
-ofwd_strategy(void *devdata, int flag, daddr_t dblk, size_t size, char *buf,
-    size_t *rsize)
+ofwd_strategy(void *devdata, int flag __unused, daddr_t dblk, size_t size,
+    char *buf, size_t *rsize)
 {
 	struct ofw_devdesc *dp = (struct ofw_devdesc *)devdata;
 	daddr_t pos;
 	int n;
 
+	if (dp != kdp) {
+		if (kdp != NULL) {
+#if !defined(__powerpc__)
+			OF_close(kdp->d_handle);
+#endif
+			kdp = NULL;
+		}
+		if ((dp->d_handle = OF_open(dp->d_path)) == -1)
+			return (ENOENT);
+		kdp = dp;
+	}
+
 	pos = dblk * 512;
 	do {
 		if (OF_seek(dp->d_handle, pos) < 0)
-			return EIO;
+			return (EIO);
 		n = OF_read(dp->d_handle, buf, size);
 		if (n < 0 && n != -2)
-			return EIO;
+			return (EIO);
 	} while (n == -2);
 	*rsize = size;
-	return 0;
+	return (0);
 }
 
 static int
 ofwd_open(struct open_file *f, ...)
 {
-	char path[256];
 	struct ofw_devdesc *dp;
-	struct opened_dev *odp;
 	va_list vl;
 
 	va_start(vl, f);
 	dp = va_arg(vl, struct ofw_devdesc *);
 	va_end(vl);
-	/*
-	 * 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;
+
+	if (dp != kdp) {
+		if (kdp != NULL) {
+			OF_close(kdp->d_handle);
+			kdp = NULL;
 		}
+		if ((dp->d_handle = OF_open(dp->d_path)) == -1) {
+			printf("%s: Could not open %s\n", __func__,
+			    dp->d_path);
+			return (ENOENT);
+		}
+		kdp = dp;
 	}
-	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);
-		free(odp);
-		return ENOENT;
-	}
-	odp->count = 1;
-	SLIST_INSERT_HEAD(&opened_devs, odp, link);
-	dp->d_handle = odp->handle;
-	return 0;
+	return (0);
 }
 
 static int
 ofwd_close(struct open_file *f)
 {
 	struct ofw_devdesc *dev = f->f_devdata;
-	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);
-			#if !defined(__powerpc__)
-				OF_close(odp->handle);
-			#endif
-				free(odp);
-			}
-			break;
-		}
+	if (dev == kdp) {
+#if !defined(__powerpc__)
+		OF_close(dev->d_handle);
+#endif
+		kdp = NULL;
 	}
-	return 0;
+	return (0);
 }
 
 static int
-ofwd_ioctl(struct open_file *f, u_long cmd, void *data)
+ofwd_ioctl(struct open_file *f __unused, u_long cmd __unused,
+    void *data __unused)
 {
 
 	return (EINVAL);
 }
 
 static void
-ofwd_print(int verbose)
+ofwd_print(int verbose __unused)
 {
 
 }
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 19 dfilter service freebsd_committer freebsd_triage 2012-06-14 20:55:36 UTC
Author: marius
Date: Thu Jun 14 19:55:19 2012
New Revision: 237091
URL: http://svn.freebsd.org/changeset/base/237091

Log:
  MFC: r236579
  
  The workaround added in r151650 for handling firmwares that don't allow
  a single device to be opened multiple times concurrently unfortunately
  isn't sufficient with ZFS. This is due to the fact, that ZFS may open
  different partitions of a single device simultaneously. So the best we
  can do in this case is to cache the lastly used device path and close
  and open devices in ofwd_strategy() as needed.
  
  PR:		165025
  Submitted by:	Gavin Mu

Modified:
  stable/9/sys/boot/ofw/libofw/ofw_disk.c
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/amd64/include/xen/   (props changed)
  stable/9/sys/boot/   (props changed)
  stable/9/sys/boot/i386/efi/   (props changed)
  stable/9/sys/boot/ia64/efi/   (props changed)
  stable/9/sys/boot/ia64/ski/   (props changed)
  stable/9/sys/boot/powerpc/boot1.chrp/   (props changed)
  stable/9/sys/boot/powerpc/ofw/   (props changed)
  stable/9/sys/cddl/contrib/opensolaris/   (props changed)
  stable/9/sys/conf/   (props changed)
  stable/9/sys/contrib/dev/acpica/   (props changed)
  stable/9/sys/contrib/octeon-sdk/   (props changed)
  stable/9/sys/contrib/pf/   (props changed)
  stable/9/sys/contrib/x86emu/   (props changed)
  stable/9/sys/dev/   (props changed)
  stable/9/sys/dev/e1000/   (props changed)
  stable/9/sys/dev/ixgbe/   (props changed)
  stable/9/sys/fs/   (props changed)
  stable/9/sys/fs/ntfs/   (props changed)
  stable/9/sys/modules/   (props changed)

Modified: stable/9/sys/boot/ofw/libofw/ofw_disk.c
==============================================================================
--- stable/9/sys/boot/ofw/libofw/ofw_disk.c	Thu Jun 14 19:30:31 2012	(r237090)
+++ stable/9/sys/boot/ofw/libofw/ofw_disk.c	Thu Jun 14 19:55:19 2012	(r237091)
@@ -31,7 +31,6 @@ __FBSDID("$FreeBSD$");
  */
 
 #include <sys/param.h>
-#include <sys/queue.h>
 
 #include <netinet/in.h>
 
@@ -43,8 +42,8 @@ __FBSDID("$FreeBSD$");
 #include "libofw.h"
 
 static int	ofwd_init(void);
-static int	ofwd_strategy(void *devdata, int flag, daddr_t dblk, 
-				size_t size, char *buf, size_t *rsize);
+static int	ofwd_strategy(void *devdata, int flag, daddr_t dblk,
+		    size_t size, char *buf, size_t *rsize);
 static int	ofwd_open(struct open_file *f, ...);
 static int	ofwd_close(struct open_file *f);
 static int	ofwd_ioctl(struct open_file *f, u_long cmd, void *data);
@@ -61,120 +60,109 @@ 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_devs);
+/*
+ * We're not guaranteed to be able to open a device more than once and there
+ * is no OFW standard method to determine whether a device is already opened.
+ * Opening a device multiple times simultaneously happens to work with most
+ * OFW block device drivers but triggers a trap with at least the driver for
+ * the on-board controllers of Sun Fire V100 and Ultra 1.  Upper layers and MI
+ * code expect to be able to open a device more than once however.  Given that
+ * different partitions of the same device might be opened at the same time as
+ * done by ZFS, we can't generally just keep track of the opened devices and
+ * reuse the instance handle when asked to open an already opened device.  So
+ * the best we can do is to cache the lastly used device path and close and
+ * open devices in ofwd_strategy() as needed.
+ */
+static struct ofw_devdesc *kdp;
 
 static int
 ofwd_init(void)
 {
 
-	return 0;
+	return (0);
 }
 
 static int
-ofwd_strategy(void *devdata, int flag, daddr_t dblk, size_t size, char *buf,
-    size_t *rsize)
+ofwd_strategy(void *devdata, int flag __unused, daddr_t dblk, size_t size,
+    char *buf, size_t *rsize)
 {
 	struct ofw_devdesc *dp = (struct ofw_devdesc *)devdata;
 	daddr_t pos;
 	int n;
 
+	if (dp != kdp) {
+		if (kdp != NULL) {
+#if !defined(__powerpc__)
+			OF_close(kdp->d_handle);
+#endif
+			kdp = NULL;
+		}
+		if ((dp->d_handle = OF_open(dp->d_path)) == -1)
+			return (ENOENT);
+		kdp = dp;
+	}
+
 	pos = dblk * 512;
 	do {
 		if (OF_seek(dp->d_handle, pos) < 0)
-			return EIO;
+			return (EIO);
 		n = OF_read(dp->d_handle, buf, size);
 		if (n < 0 && n != -2)
-			return EIO;
+			return (EIO);
 	} while (n == -2);
 	*rsize = size;
-	return 0;
+	return (0);
 }
 
 static int
 ofwd_open(struct open_file *f, ...)
 {
-	char path[256];
 	struct ofw_devdesc *dp;
-	struct opened_dev *odp;
 	va_list vl;
 
 	va_start(vl, f);
 	dp = va_arg(vl, struct ofw_devdesc *);
 	va_end(vl);
-	/*
-	 * 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;
+
+	if (dp != kdp) {
+		if (kdp != NULL) {
+			OF_close(kdp->d_handle);
+			kdp = NULL;
 		}
+		if ((dp->d_handle = OF_open(dp->d_path)) == -1) {
+			printf("%s: Could not open %s\n", __func__,
+			    dp->d_path);
+			return (ENOENT);
+		}
+		kdp = dp;
 	}
-	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);
-		free(odp);
-		return ENOENT;
-	}
-	odp->count = 1;
-	SLIST_INSERT_HEAD(&opened_devs, odp, link);
-	dp->d_handle = odp->handle;
-	return 0;
+	return (0);
 }
 
 static int
 ofwd_close(struct open_file *f)
 {
 	struct ofw_devdesc *dev = f->f_devdata;
-	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);
-			#if !defined(__powerpc__)
-				OF_close(odp->handle);
-			#endif
-				free(odp);
-			}
-			break;
-		}
+	if (dev == kdp) {
+#if !defined(__powerpc__)
+		OF_close(dev->d_handle);
+#endif
+		kdp = NULL;
 	}
-	return 0;
+	return (0);
 }
 
 static int
-ofwd_ioctl(struct open_file *f, u_long cmd, void *data)
+ofwd_ioctl(struct open_file *f __unused, u_long cmd __unused,
+    void *data __unused)
 {
 
 	return (EINVAL);
 }
 
 static void
-ofwd_print(int verbose)
+ofwd_print(int verbose __unused)
 {
 
 }
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 20 dfilter service freebsd_committer freebsd_triage 2012-06-14 20:55:56 UTC
Author: marius
Date: Thu Jun 14 19:55:22 2012
New Revision: 237092
URL: http://svn.freebsd.org/changeset/base/237092

Log:
  MFC: r236579
  
  The workaround added in r151650 for handling firmwares that don't allow
  a single device to be opened multiple times concurrently unfortunately
  isn't sufficient with ZFS. This is due to the fact, that ZFS may open
  different partitions of a single device simultaneously. So the best we
  can do in this case is to cache the lastly used device path and close
  and open devices in ofwd_strategy() as needed.
  
  PR:		165025
  Submitted by:	Gavin Mu

Modified:
  stable/8/sys/boot/ofw/libofw/ofw_disk.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/boot/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/e1000/   (props changed)

Modified: stable/8/sys/boot/ofw/libofw/ofw_disk.c
==============================================================================
--- stable/8/sys/boot/ofw/libofw/ofw_disk.c	Thu Jun 14 19:55:19 2012	(r237091)
+++ stable/8/sys/boot/ofw/libofw/ofw_disk.c	Thu Jun 14 19:55:22 2012	(r237092)
@@ -31,7 +31,6 @@ __FBSDID("$FreeBSD$");
  */
 
 #include <sys/param.h>
-#include <sys/queue.h>
 
 #include <netinet/in.h>
 
@@ -43,8 +42,8 @@ __FBSDID("$FreeBSD$");
 #include "libofw.h"
 
 static int	ofwd_init(void);
-static int	ofwd_strategy(void *devdata, int flag, daddr_t dblk, 
-				size_t size, char *buf, size_t *rsize);
+static int	ofwd_strategy(void *devdata, int flag, daddr_t dblk,
+		    size_t size, char *buf, size_t *rsize);
 static int	ofwd_open(struct open_file *f, ...);
 static int	ofwd_close(struct open_file *f);
 static int	ofwd_ioctl(struct open_file *f, u_long cmd, void *data);
@@ -61,120 +60,109 @@ 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_devs);
+/*
+ * We're not guaranteed to be able to open a device more than once and there
+ * is no OFW standard method to determine whether a device is already opened.
+ * Opening a device multiple times simultaneously happens to work with most
+ * OFW block device drivers but triggers a trap with at least the driver for
+ * the on-board controllers of Sun Fire V100 and Ultra 1.  Upper layers and MI
+ * code expect to be able to open a device more than once however.  Given that
+ * different partitions of the same device might be opened at the same time as
+ * done by ZFS, we can't generally just keep track of the opened devices and
+ * reuse the instance handle when asked to open an already opened device.  So
+ * the best we can do is to cache the lastly used device path and close and
+ * open devices in ofwd_strategy() as needed.
+ */
+static struct ofw_devdesc *kdp;
 
 static int
 ofwd_init(void)
 {
 
-	return 0;
+	return (0);
 }
 
 static int
-ofwd_strategy(void *devdata, int flag, daddr_t dblk, size_t size, char *buf,
-    size_t *rsize)
+ofwd_strategy(void *devdata, int flag __unused, daddr_t dblk, size_t size,
+    char *buf, size_t *rsize)
 {
 	struct ofw_devdesc *dp = (struct ofw_devdesc *)devdata;
 	daddr_t pos;
 	int n;
 
+	if (dp != kdp) {
+		if (kdp != NULL) {
+#if !defined(__powerpc__)
+			OF_close(kdp->d_handle);
+#endif
+			kdp = NULL;
+		}
+		if ((dp->d_handle = OF_open(dp->d_path)) == -1)
+			return (ENOENT);
+		kdp = dp;
+	}
+
 	pos = dblk * 512;
 	do {
 		if (OF_seek(dp->d_handle, pos) < 0)
-			return EIO;
+			return (EIO);
 		n = OF_read(dp->d_handle, buf, size);
 		if (n < 0 && n != -2)
-			return EIO;
+			return (EIO);
 	} while (n == -2);
 	*rsize = size;
-	return 0;
+	return (0);
 }
 
 static int
 ofwd_open(struct open_file *f, ...)
 {
-	char path[256];
 	struct ofw_devdesc *dp;
-	struct opened_dev *odp;
 	va_list vl;
 
 	va_start(vl, f);
 	dp = va_arg(vl, struct ofw_devdesc *);
 	va_end(vl);
-	/*
-	 * 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;
+
+	if (dp != kdp) {
+		if (kdp != NULL) {
+			OF_close(kdp->d_handle);
+			kdp = NULL;
 		}
+		if ((dp->d_handle = OF_open(dp->d_path)) == -1) {
+			printf("%s: Could not open %s\n", __func__,
+			    dp->d_path);
+			return (ENOENT);
+		}
+		kdp = dp;
 	}
-	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);
-		free(odp);
-		return ENOENT;
-	}
-	odp->count = 1;
-	SLIST_INSERT_HEAD(&opened_devs, odp, link);
-	dp->d_handle = odp->handle;
-	return 0;
+	return (0);
 }
 
 static int
 ofwd_close(struct open_file *f)
 {
 	struct ofw_devdesc *dev = f->f_devdata;
-	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);
-			#if !defined(__powerpc__)
-				OF_close(odp->handle);
-			#endif
-				free(odp);
-			}
-			break;
-		}
+	if (dev == kdp) {
+#if !defined(__powerpc__)
+		OF_close(dev->d_handle);
+#endif
+		kdp = NULL;
 	}
-	return 0;
+	return (0);
 }
 
 static int
-ofwd_ioctl(struct open_file *f, u_long cmd, void *data)
+ofwd_ioctl(struct open_file *f __unused, u_long cmd __unused,
+    void *data __unused)
 {
 
 	return (EINVAL);
 }
 
 static void
-ofwd_print(int verbose)
+ofwd_print(int verbose __unused)
 {
 
 }
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 21 Marius Strobl freebsd_committer freebsd_triage 2012-06-14 21:03:27 UTC
State Changed
From-To: open->closed

Close, thanks for submitting!