[Zrouter-src-freebsd] ZRouter.org: push to FreeBSD HEAD tree

zrouter-src-freebsd at zrouter.org zrouter-src-freebsd at zrouter.org
Wed Jul 25 14:36:14 UTC 2012


details:   http://zrouter.org/hg/FreeBSD/head//rev/58b18bd1429e
changeset: 496:58b18bd1429e
user:      Aleksandr Rybalko <ray at ddteam.net>
date:      Wed Jul 25 16:45:04 2012 +0300
description:
Lazy update

diffstat:

 head/sys/boot/Makefile.sparc64                                         |      3 +-
 head/sys/boot/arm/at91/boot0spi/main.c                                 |     18 +-
 head/sys/boot/arm/at91/boot2/boot2.c                                   |     14 +-
 head/sys/boot/arm/at91/bootspi/ee.c                                    |     10 +-
 head/sys/boot/arm/at91/libat91/Makefile                                |      6 +-
 head/sys/boot/arm/at91/libat91/at91rm9200.h                            |      6 +-
 head/sys/boot/arm/at91/libat91/at91rm9200_lowlevel.c                   |      6 +-
 head/sys/boot/arm/at91/libat91/eeprom.c                                |     10 +-
 head/sys/boot/arm/at91/libat91/emac_init.c                             |     30 +-
 head/sys/boot/arm/at91/libat91/lib_AT91RM9200.h                        |     14 +-
 head/sys/boot/arm/at91/libat91/spi_flash.c                             |     10 +-
 head/sys/boot/arm/at91/linker.cfg                                      |    234 +-
 head/sys/boot/arm/ixp425/boot2/boot2.c                                 |      9 +-
 head/sys/boot/arm/uboot/Makefile                                       |     29 +-
 head/sys/boot/arm/uboot/conf.c                                         |      5 +-
 head/sys/boot/arm/uboot/ldscript.arm                                   |      4 +-
 head/sys/boot/arm/uboot/start.S                                        |     13 +-
 head/sys/boot/arm/uboot/version                                        |      3 +-
 head/sys/boot/common/boot.c                                            |     20 +-
 head/sys/boot/common/bootstrap.h                                       |     16 +-
 head/sys/boot/common/load_elf.c                                        |      4 +-
 head/sys/boot/common/load_elf_obj.c                                    |      4 +-
 head/sys/boot/common/loader.8                                          |      4 +-
 head/sys/boot/common/ufsread.c                                         |     18 +-
 head/sys/boot/fdt/dts/bindings-localbus.txt                            |     83 +
 head/sys/boot/fdt/dts/db78100.dts                                      |     21 +-
 head/sys/boot/fdt/dts/db88f6281.dts                                    |     50 +-
 head/sys/boot/fdt/dts/p2041rdb.dts                                     |    490 +
 head/sys/boot/fdt/dts/p2041si.dtsi                                     |   1296 +
 head/sys/boot/fdt/dts/p3041ds.dts                                      |    998 +-
 head/sys/boot/fdt/dts/p3041si.dtsi                                     |   1339 +
 head/sys/boot/fdt/dts/p5020ds.dts                                      |    583 +
 head/sys/boot/fdt/dts/p5020si.dtsi                                     |   1389 +
 head/sys/boot/fdt/dts/sheevaplug.dts                                   |     45 +-
 head/sys/boot/fdt/fdt_loader_cmd.c                                     |    107 +-
 head/sys/boot/forth/beastie.4th                                        |      4 +-
 head/sys/boot/forth/beastie.4th.8                                      |      6 +-
 head/sys/boot/forth/brand.4th                                          |      4 +-
 head/sys/boot/forth/brand.4th.8                                        |      6 +-
 head/sys/boot/forth/check-password.4th                                 |      4 +-
 head/sys/boot/forth/check-password.4th.8                               |      6 +-
 head/sys/boot/forth/color.4th                                          |      4 +-
 head/sys/boot/forth/color.4th.8                                        |      6 +-
 head/sys/boot/forth/delay.4th                                          |      4 +-
 head/sys/boot/forth/delay.4th.8                                        |      6 +-
 head/sys/boot/forth/menu-commands.4th                                  |      4 +-
 head/sys/boot/forth/menu.4th                                           |      4 +-
 head/sys/boot/forth/menu.4th.8                                         |      6 +-
 head/sys/boot/forth/shortcuts.4th                                      |      4 +-
 head/sys/boot/forth/version.4th                                        |      4 +-
 head/sys/boot/forth/version.4th.8                                      |      6 +-
 head/sys/boot/i386/boot2/boot2.c                                       |     13 +-
 head/sys/boot/i386/btx/btx/Makefile                                    |      3 +-
 head/sys/boot/i386/btx/btx/btx.S                                       |      6 +-
 head/sys/boot/i386/btx/btxldr/Makefile                                 |      3 +-
 head/sys/boot/i386/btx/btxldr/btxldr.S                                 |     24 +-
 head/sys/boot/i386/btx/lib/Makefile                                    |      5 +-
 head/sys/boot/i386/btx/lib/btxcsu.S                                    |     49 +
 head/sys/boot/i386/btx/lib/btxcsu.s                                    |     51 -
 head/sys/boot/i386/cdboot/Makefile                                     |     10 +-
 head/sys/boot/i386/cdboot/cdboot.S                                     |    597 +
 head/sys/boot/i386/cdboot/cdboot.s                                     |    600 -
 head/sys/boot/i386/common/bootargs.h                                   |     69 +
 head/sys/boot/i386/efi/reloc.c                                         |     13 +-
 head/sys/boot/i386/gptboot/gptboot.c                                   |      9 +-
 head/sys/boot/i386/libi386/Makefile                                    |      4 +-
 head/sys/boot/i386/libi386/biosdisk.c                                  |      3 +-
 head/sys/boot/i386/libi386/biospnp.c                                   |      3 +-
 head/sys/boot/i386/libi386/devicename.c                                |     13 +-
 head/sys/boot/i386/libi386/libi386.h                                   |     14 +-
 head/sys/boot/i386/loader/Makefile                                     |     13 +-
 head/sys/boot/i386/loader/conf.c                                       |     16 +-
 head/sys/boot/i386/loader/main.c                                       |    114 +-
 head/sys/boot/i386/pxeldr/Makefile                                     |      4 +-
 head/sys/boot/i386/pxeldr/pxeldr.S                                     |      8 +-
 head/sys/boot/i386/zfsboot/zfsboot.c                                   |     73 +-
 head/sys/boot/ofw/libofw/Makefile                                      |      4 +-
 head/sys/boot/ofw/libofw/devicename.c                                  |     23 +-
 head/sys/boot/ofw/libofw/libofw.h                                      |     10 +-
 head/sys/boot/ofw/libofw/ofw_disk.c                                    |    124 +-
 head/sys/boot/pc98/boot2/boot2.c                                       |      9 +-
 head/sys/boot/pc98/btx/btx/Makefile                                    |      3 +-
 head/sys/boot/pc98/btx/btx/btx.S                                       |      6 +-
 head/sys/boot/pc98/btx/btxldr/Makefile                                 |      3 +-
 head/sys/boot/pc98/btx/btxldr/btxldr.S                                 |     24 +-
 head/sys/boot/pc98/btx/lib/Makefile                                    |      5 +-
 head/sys/boot/pc98/btx/lib/btxcsu.S                                    |     49 +
 head/sys/boot/pc98/btx/lib/btxcsu.s                                    |     51 -
 head/sys/boot/pc98/cdboot/Makefile                                     |      6 +-
 head/sys/boot/pc98/cdboot/cdboot.S                                     |    808 +
 head/sys/boot/pc98/cdboot/cdboot.s                                     |    811 -
 head/sys/boot/pc98/libpc98/Makefile                                    |      4 +-
 head/sys/boot/pc98/libpc98/biosdisk.c                                  |      3 +-
 head/sys/boot/pc98/loader/main.c                                       |     20 +-
 head/sys/boot/powerpc/boot1.chrp/boot1.c                               |      5 +-
 head/sys/boot/sparc64/Makefile                                         |      4 +-
 head/sys/boot/sparc64/boot1/Makefile                                   |     13 +-
 head/sys/boot/sparc64/boot1/boot1.c                                    |    139 +-
 head/sys/boot/sparc64/loader/Makefile                                  |     29 +-
 head/sys/boot/sparc64/loader/main.c                                    |    107 +-
 head/sys/boot/sparc64/zfsboot/Makefile                                 |      9 +
 head/sys/boot/sparc64/zfsloader/Makefile                               |      9 +
 head/sys/boot/uboot/common/metadata.c                                  |     17 +-
 head/sys/boot/uboot/lib/api_public.h                                   |      3 +-
 head/sys/boot/uboot/lib/copy.c                                         |     50 +-
 head/sys/boot/uboot/lib/devicename.c                                   |      9 +-
 head/sys/boot/uboot/lib/disk.c                                         |     99 +-
 head/sys/boot/uboot/lib/elf_freebsd.c                                  |      9 +-
 head/sys/boot/uboot/lib/glue.c                                         |      5 +-
 head/sys/boot/uboot/lib/libuboot.h                                     |      4 +-
 head/sys/boot/userboot/libstand/Makefile                               |     19 +-
 head/sys/boot/zfs/devicename_stubs.c                                   |     47 +
 head/sys/boot/zfs/libzfs.h                                             |     66 +
 head/sys/boot/zfs/zfs.c                                                |    256 +-
 head/sys/boot/zfs/zfsimpl.c                                            |    444 +-
 head/sys/cam/ata/ata_all.c                                             |    120 +-
 head/sys/cam/ata/ata_all.h                                             |     38 +-
 head/sys/cam/ata/ata_da.c                                              |    147 +-
 head/sys/cam/ata/ata_pmp.c                                             |     60 +-
 head/sys/cam/ata/ata_xpt.c                                             |    551 +-
 head/sys/cam/cam.h                                                     |     11 +-
 head/sys/cam/cam_ccb.h                                                 |     16 +-
 head/sys/cam/cam_debug.h                                               |     52 +-
 head/sys/cam/cam_periph.c                                              |    650 +-
 head/sys/cam/cam_periph.h                                              |      3 +-
 head/sys/cam/cam_sim.h                                                 |      3 +-
 head/sys/cam/cam_xpt.c                                                 |    145 +-
 head/sys/cam/cam_xpt.h                                                 |     24 +-
 head/sys/cam/cam_xpt_periph.h                                          |      5 +-
 head/sys/cam/cam_xpt_sim.h                                             |      4 +-
 head/sys/cam/ctl/ctl.c                                                 |     14 +-
 head/sys/cam/ctl/ctl_backend.c                                         |      7 +-
 head/sys/cam/ctl/ctl_frontend_cam_sim.c                                |      7 +-
 head/sys/cam/ctl/ctl_frontend_internal.c                               |      7 +-
 head/sys/cam/ctl/scsi_ctl.c                                            |     61 +-
 head/sys/cam/scsi/scsi_all.c                                           |    298 +-
 head/sys/cam/scsi/scsi_all.h                                           |     49 +-
 head/sys/cam/scsi/scsi_cd.c                                            |    123 +-
 head/sys/cam/scsi/scsi_ch.c                                            |     28 +-
 head/sys/cam/scsi/scsi_da.c                                            |    238 +-
 head/sys/cam/scsi/scsi_da.h                                            |      3 +-
 head/sys/cam/scsi/scsi_enc.c                                           |   1023 +
 head/sys/cam/scsi/scsi_enc.h                                           |    219 +
 head/sys/cam/scsi/scsi_enc_internal.h                                  |    230 +
 head/sys/cam/scsi/scsi_enc_safte.c                                     |   1137 +
 head/sys/cam/scsi/scsi_enc_ses.c                                       |   2816 ++
 head/sys/cam/scsi/scsi_pass.c                                          |    109 +-
 head/sys/cam/scsi/scsi_pt.c                                            |     13 +-
 head/sys/cam/scsi/scsi_sa.c                                            |      8 +-
 head/sys/cam/scsi/scsi_ses.c                                           |   2533 --
 head/sys/cam/scsi/scsi_ses.h                                           |   2452 +-
 head/sys/cam/scsi/scsi_sg.c                                            |     27 +-
 head/sys/cam/scsi/scsi_target.c                                        |      6 +-
 head/sys/cam/scsi/scsi_xpt.c                                           |     93 +-
 head/sys/cddl/boot/zfs/zfsimpl.h                                       |     16 +-
 head/sys/cddl/contrib/opensolaris/common/nvpair/fnvpair.c              |    498 +
 head/sys/cddl/contrib/opensolaris/common/zfs/zfeature_common.c         |    155 +
 head/sys/cddl/contrib/opensolaris/common/zfs/zfeature_common.h         |     70 +
 head/sys/cddl/contrib/opensolaris/common/zfs/zpool_prop.c              |     26 +-
 head/sys/cddl/contrib/opensolaris/uts/common/Makefile.files            |     10 +-
 head/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c           |    107 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c              |      4 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/bptree.c           |    224 +
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c             |      3 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/ddt.c              |      9 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu.c              |    126 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c         |    280 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_traverse.c     |    107 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_tx.c           |      5 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dnode.c            |     19 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dnode_sync.c       |      4 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c      |    202 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_deleg.c        |      8 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_pool.c         |     57 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scan.c         |    187 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sa.c               |     16 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c              |    483 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa_config.c       |      9 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa_misc.c         |     57 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/space_map.c        |      5 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/bptree.h       |     64 +
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu.h          |    101 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu_impl.h     |     30 +
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu_traverse.h |      4 +
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h  |     13 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_pool.h     |      9 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_scan.h     |      4 +
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa.h          |     17 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa_impl.h     |      9 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/vdev.h         |      5 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/vdev_impl.h    |      8 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zap.h          |      9 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfeature.h     |     52 +
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h          |     14 +
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio_impl.h     |      2 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev.c             |     30 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_disk.c        |     64 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_file.c        |      6 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c        |      7 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_label.c       |    103 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_mirror.c      |      8 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_missing.c     |      8 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_raidz.c       |      6 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_root.c        |      8 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zap.c              |     14 +
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zap_micro.c        |      6 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfeature.c         |    414 +
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c        |     92 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c       |      2 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c        |     11 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c        |      2 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c              |     46 +-
 head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c             |     12 +-
 head/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h              |     34 +
 head/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h              |     28 +-
 head/sys/cddl/contrib/opensolaris/uts/common/sys/nvpair.h              |     68 +
 head/sys/cddl/dev/dtrace/amd64/dis_tables.c                            |     12 +-
 head/sys/cddl/dev/dtrace/amd64/dtrace_subr.c                           |     32 +-
 head/sys/cddl/dev/dtrace/i386/dis_tables.c                             |     12 +-
 head/sys/cddl/dev/dtrace/i386/dtrace_subr.c                            |     32 +-
 head/sys/compat/freebsd32/freebsd32.h                                  |      4 +-
 head/sys/compat/freebsd32/freebsd32_misc.c                             |      5 +-
 head/sys/compat/freebsd32/freebsd32_proto.h                            |    132 +-
 head/sys/compat/freebsd32/freebsd32_syscall.h                          |      4 +-
 head/sys/compat/freebsd32/freebsd32_syscalls.c                         |      4 +-
 head/sys/compat/freebsd32/freebsd32_sysent.c                           |      4 +-
 head/sys/compat/freebsd32/freebsd32_systrace_args.c                    |    238 +-
 head/sys/compat/freebsd32/syscalls.master                              |     76 +-
 head/sys/compat/ia32/ia32_sysvec.c                                     |      4 +-
 head/sys/compat/ia32/ia32_util.h                                       |     19 +-
 head/sys/compat/linux/check_error.d                                    |    144 +
 head/sys/compat/linux/check_internal_locks.d                           |    132 +
 head/sys/compat/linux/linux_dtrace.h                                   |     95 +
 head/sys/compat/linux/linux_emul.c                                     |    127 +-
 head/sys/compat/linux/linux_emul.h                                     |     43 +-
 head/sys/compat/linux/linux_file.c                                     |      7 +-
 head/sys/compat/linux/linux_fork.c                                     |     12 +-
 head/sys/compat/linux/linux_futex.c                                    |    511 +-
 head/sys/compat/linux/linux_mib.c                                      |    316 +-
 head/sys/compat/linux/linux_misc.c                                     |     16 +-
 head/sys/compat/linux/linux_sysctl.c                                   |     60 +-
 head/sys/compat/linux/linux_time.c                                     |    231 +-
 head/sys/compat/linux/linux_uid16.c                                    |    191 +-
 head/sys/compat/linux/linux_util.c                                     |    124 +-
 head/sys/compat/linux/linux_util.h                                     |     10 +-
 head/sys/compat/linux/stats_timing.d                                   |     94 +
 head/sys/compat/linux/trace_futexes.d                                  |    182 +
 head/sys/compat/ndis/subr_ntoskrnl.c                                   |      3 +-
 head/sys/contrib/dev/acpica/acpica_prep.sh                             |     11 +-
 head/sys/contrib/dev/acpica/changes.txt                                |    277 +-
 head/sys/contrib/dev/acpica/common/adfile.c                            |     19 +-
 head/sys/contrib/dev/acpica/common/adwalk.c                            |     30 +-
 head/sys/contrib/dev/acpica/common/ahpredef.c                          |    323 +
 head/sys/contrib/dev/acpica/common/dmextern.c                          |     36 +-
 head/sys/contrib/dev/acpica/common/dmrestag.c                          |     21 +-
 head/sys/contrib/dev/acpica/compiler/aslcompile.c                      |    178 +-
 head/sys/contrib/dev/acpica/compiler/aslcompiler.h                     |     24 +-
 head/sys/contrib/dev/acpica/compiler/aslcompiler.l                     |    712 +-
 head/sys/contrib/dev/acpica/compiler/aslcompiler.y                     |    228 +-
 head/sys/contrib/dev/acpica/compiler/aslerror.c                        |     40 +-
 head/sys/contrib/dev/acpica/compiler/aslfiles.c                        |    184 +-
 head/sys/contrib/dev/acpica/compiler/aslglobal.h                       |      5 +-
 head/sys/contrib/dev/acpica/compiler/asllookup.c                       |      2 +-
 head/sys/contrib/dev/acpica/compiler/aslmain.c                         |     91 +-
 head/sys/contrib/dev/acpica/compiler/aslmap.c                          |      3 +-
 head/sys/contrib/dev/acpica/compiler/aslmessages.h                     |     11 +-
 head/sys/contrib/dev/acpica/compiler/aslrestype1.c                     |      8 +
 head/sys/contrib/dev/acpica/compiler/aslstartup.c                      |     78 +-
 head/sys/contrib/dev/acpica/compiler/aslsupport.l                      |    804 +
 head/sys/contrib/dev/acpica/compiler/aslutils.c                        |     90 +-
 head/sys/contrib/dev/acpica/compiler/dtio.c                            |     60 +-
 head/sys/contrib/dev/acpica/compiler/dttemplate.c                      |      2 +-
 head/sys/contrib/dev/acpica/compiler/preprocess.h                      |     17 -
 head/sys/contrib/dev/acpica/compiler/prscan.c                          |     73 +-
 head/sys/contrib/dev/acpica/compiler/prutils.c                         |    125 +-
 head/sys/contrib/dev/acpica/components/debugger/dbcmds.c               |    120 +-
 head/sys/contrib/dev/acpica/components/debugger/dbdisply.c             |     15 +-
 head/sys/contrib/dev/acpica/components/debugger/dbexec.c               |      6 +-
 head/sys/contrib/dev/acpica/components/debugger/dbfileio.c             |     13 +
 head/sys/contrib/dev/acpica/components/debugger/dbinput.c              |      4 +-
 head/sys/contrib/dev/acpica/components/debugger/dbstats.c              |     28 +-
 head/sys/contrib/dev/acpica/components/debugger/dbutils.c              |      9 +-
 head/sys/contrib/dev/acpica/components/disassembler/dmopcode.c         |    213 +
 head/sys/contrib/dev/acpica/components/disassembler/dmwalk.c           |     55 +-
 head/sys/contrib/dev/acpica/components/dispatcher/dsfield.c            |     88 +-
 head/sys/contrib/dev/acpica/components/dispatcher/dsopcode.c           |     14 +-
 head/sys/contrib/dev/acpica/components/events/evgpe.c                  |     15 +-
 head/sys/contrib/dev/acpica/components/events/evgpeutil.c              |     19 +
 head/sys/contrib/dev/acpica/components/events/evmisc.c                 |    203 +-
 head/sys/contrib/dev/acpica/components/events/evxface.c                |    362 +-
 head/sys/contrib/dev/acpica/components/events/evxfgpe.c                |     86 +-
 head/sys/contrib/dev/acpica/components/executer/exconfig.c             |      2 +-
 head/sys/contrib/dev/acpica/components/executer/exdump.c               |     29 +-
 head/sys/contrib/dev/acpica/components/executer/exprep.c               |      4 +-
 head/sys/contrib/dev/acpica/components/executer/exresolv.c             |      2 +-
 head/sys/contrib/dev/acpica/components/executer/exstore.c              |      6 +-
 head/sys/contrib/dev/acpica/components/executer/exutils.c              |      2 +-
 head/sys/contrib/dev/acpica/components/hardware/hwesleep.c             |      8 +-
 head/sys/contrib/dev/acpica/components/hardware/hwsleep.c              |     25 -
 head/sys/contrib/dev/acpica/components/hardware/hwxfsleep.c            |      8 +
 head/sys/contrib/dev/acpica/components/namespace/nspredef.c            |      2 +-
 head/sys/contrib/dev/acpica/components/parser/psxface.c                |      4 +-
 head/sys/contrib/dev/acpica/components/resources/rscreate.c            |      6 +-
 head/sys/contrib/dev/acpica/components/resources/rsutils.c             |      2 +-
 head/sys/contrib/dev/acpica/components/tables/tbfadt.c                 |     64 +-
 head/sys/contrib/dev/acpica/components/tables/tbinstal.c               |      5 +-
 head/sys/contrib/dev/acpica/components/tables/tbutils.c                |     45 +-
 head/sys/contrib/dev/acpica/components/tables/tbxface.c                |    169 +-
 head/sys/contrib/dev/acpica/components/tables/tbxfload.c               |    415 +
 head/sys/contrib/dev/acpica/components/tables/tbxfroot.c               |      2 +-
 head/sys/contrib/dev/acpica/components/utilities/utdecode.c            |     62 +-
 head/sys/contrib/dev/acpica/components/utilities/utdelete.c            |     21 +-
 head/sys/contrib/dev/acpica/components/utilities/utexcep.c             |    174 +
 head/sys/contrib/dev/acpica/components/utilities/utglobal.c            |      9 +-
 head/sys/contrib/dev/acpica/components/utilities/utmisc.c              |     87 +-
 head/sys/contrib/dev/acpica/components/utilities/utobject.c            |      6 +-
 head/sys/contrib/dev/acpica/components/utilities/utresrc.c             |      4 +-
 head/sys/contrib/dev/acpica/components/utilities/uttrack.c             |      6 +-
 head/sys/contrib/dev/acpica/components/utilities/utxferror.c           |     81 +
 head/sys/contrib/dev/acpica/include/acdebug.h                          |      5 +-
 head/sys/contrib/dev/acpica/include/acdisasm.h                         |      8 +
 head/sys/contrib/dev/acpica/include/acexcep.h                          |      5 +-
 head/sys/contrib/dev/acpica/include/acglobal.h                         |     22 +-
 head/sys/contrib/dev/acpica/include/aclocal.h                          |     45 +-
 head/sys/contrib/dev/acpica/include/acmacros.h                         |      4 +-
 head/sys/contrib/dev/acpica/include/acobject.h                         |     15 +-
 head/sys/contrib/dev/acpica/include/acoutput.h                         |      4 +
 head/sys/contrib/dev/acpica/include/acpiosxf.h                         |      2 +-
 head/sys/contrib/dev/acpica/include/acpixf.h                           |     36 +-
 head/sys/contrib/dev/acpica/include/acpredef.h                         |      6 +-
 head/sys/contrib/dev/acpica/include/actbl1.h                           |      2 +-
 head/sys/contrib/dev/acpica/include/actypes.h                          |      7 +-
 head/sys/contrib/dev/acpica/include/acutils.h                          |      6 +-
 head/sys/contrib/dev/acpica/include/platform/acenv.h                   |      2 +-
 head/sys/contrib/dev/acpica/os_specific/service_layers/osunixxf.c      |     21 +
 head/sys/contrib/dev/iwn/iwlwifi-6000g2a-17.168.5.3.fw.uu              |   7833 ++++++
 head/sys/contrib/dev/iwn/iwlwifi-6000g2b-18.168.6.1.fw.uu              |  11961 ++++++++++
 head/sys/contrib/dev/ral/LICENSE.orig                                  |     16 +
 head/sys/contrib/dev/ral/rt2561.fw.uu.orig                             |    202 +
 head/sys/contrib/dev/ral/rt2561s.fw.uu.orig                            |    202 +
 head/sys/contrib/dev/ral/rt2661.fw.uu.orig                             |    202 +
 head/sys/contrib/dev/ral/rt2860.fw.uu.orig                             |    202 +
 head/sys/contrib/libfdt/fdt.c                                          |      9 +
 head/sys/contrib/libfdt/fdt_empty_tree.c                               |     84 +
 head/sys/contrib/libfdt/fdt_ro.c                                       |    125 +-
 head/sys/contrib/libfdt/fdt_rw.c                                       |     27 +
 head/sys/contrib/libfdt/libfdt.h                                       |    378 +-
 head/sys/contrib/libfdt/libfdt_env.h                                   |     16 +-
 head/sys/contrib/libfdt/libfdt_internal.h                              |      1 +
 head/sys/contrib/pf/net/pf.c                                           |      6 +-
 head/sys/contrib/pf/net/pf_if.c                                        |      5 +-
 head/sys/contrib/pf/net/pf_ioctl.c                                     |      6 +-
 head/sys/contrib/pf/net/pf_table.c                                     |      3 +-
 head/sys/contrib/pf/net/pfvar.h                                        |      2 +
 head/sys/contrib/rdma/krping/krping.c                                  |     50 +-
 head/sys/contrib/rdma/krping/krping.h                                  |      6 +-
 head/sys/contrib/rdma/krping/krping_dev.c                              |      8 +-
 head/sys/contrib/rdma/rdma_addr.c                                      |      7 +-
 head/sys/contrib/rdma/rdma_cache.c                                     |      4 +-
 head/sys/geom/bde/g_bde.c                                              |      8 +-
 head/sys/geom/eli/g_eli.c                                              |      4 +-
 head/sys/geom/eli/g_eli.h                                              |     19 +-
 head/sys/geom/eli/g_eli_ctl.c                                          |      8 +-
 head/sys/geom/eli/g_eli_integrity.c                                    |      9 +-
 head/sys/geom/eli/g_eli_key.c                                          |      6 +-
 head/sys/geom/eli/g_eli_key_cache.c                                    |     12 +-
 head/sys/geom/gate/g_gate.c                                            |    322 +-
 head/sys/geom/gate/g_gate.h                                            |     31 +-
 head/sys/geom/geom.h                                                   |      9 +-
 head/sys/geom/geom_aes.c                                               |      6 +-
 head/sys/geom/geom_dev.c                                               |      4 +-
 head/sys/geom/geom_disk.c                                              |     75 +-
 head/sys/geom/geom_disk.h                                              |      8 +-
 head/sys/geom/geom_flashmap.c                                          |    256 +
 head/sys/geom/geom_map.c                                               |     21 +-
 head/sys/geom/geom_slice.c                                             |      6 +-
 head/sys/geom/geom_subr.c                                              |     88 +-
 head/sys/geom/label/g_label_ufs.c                                      |      8 +-
 head/sys/geom/mirror/g_mirror.c                                        |     28 +-
 head/sys/geom/mirror/g_mirror.h                                        |      7 +-
 head/sys/geom/mirror/g_mirror_ctl.c                                    |     15 +-
 head/sys/geom/mountver/g_mountver.c                                    |     16 +-
 head/sys/geom/multipath/g_multipath.c                                  |     31 +-
 head/sys/geom/nop/g_nop.c                                              |     30 +-
 head/sys/geom/nop/g_nop.h                                              |      3 +-
 head/sys/geom/part/g_part.c                                            |     14 +-
 head/sys/geom/part/g_part.h                                            |      3 +-
 head/sys/geom/part/g_part_apm.c                                        |      9 +-
 head/sys/geom/part/g_part_bsd.c                                        |      9 +-
 head/sys/geom/part/g_part_gpt.c                                        |     27 +-
 head/sys/geom/part/g_part_vtoc8.c                                      |      9 +-
 head/sys/geom/raid/g_raid.c                                            |    178 +-
 head/sys/geom/raid/g_raid.h                                            |     41 +-
 head/sys/geom/raid/g_raid_ctl.c                                        |      4 +-
 head/sys/geom/raid/g_raid_md_if.m                                      |     21 +-
 head/sys/geom/raid/md_ddf.c                                            |   3068 ++
 head/sys/geom/raid/md_ddf.h                                            |    345 +
 head/sys/geom/raid/md_intel.c                                          |      7 +-
 head/sys/geom/raid/md_jmicron.c                                        |      5 +-
 head/sys/geom/raid/md_nvidia.c                                         |      5 +-
 head/sys/geom/raid/md_promise.c                                        |      7 +-
 head/sys/geom/raid/md_sii.c                                            |      5 +-
 head/sys/geom/raid/tr_raid1.c                                          |     16 +-
 head/sys/geom/raid/tr_raid1e.c                                         |     26 +-
 head/sys/geom/raid/tr_raid5.c                                          |    112 +-
 head/sys/geom/uncompress/g_uncompress.c                                |      6 +-
 head/sys/geom/uzip/g_uzip.c                                            |      6 +-
 head/sys/gnu/fs/reiserfs/reiserfs_inode.c                              |      6 +-
 head/sys/gnu/fs/xfs/FreeBSD/xfs_buf.c                                  |      6 +-
 head/sys/ofed/drivers/infiniband/core/cma.c                            |     21 +-
 head/sys/ofed/drivers/infiniband/core/iwcm.c                           |      3 +
 head/sys/ofed/drivers/net/mlx4/en_netdev.c                             |      2 +-
 head/sys/ofed/include/linux/net.h                                      |      8 +-
 head/sys/ofed/include/linux/workqueue.h                                |      2 +-
 head/sys/ofed/include/net/netevent.h                                   |      7 +-
 head/sys/ofed/include/rdma/iw_cm.h                                     |      4 +-
 head/sys/security/mac_mls/mac_mls.c                                    |      5 +-
 head/sys/ufs/ffs/ffs_alloc.c                                           |      9 +-
 head/sys/ufs/ffs/ffs_extern.h                                          |      4 +-
 head/sys/ufs/ffs/ffs_inode.c                                           |      7 +-
 head/sys/ufs/ffs/ffs_snapshot.c                                        |     12 +-
 head/sys/ufs/ffs/ffs_softdep.c                                         |     79 +-
 head/sys/ufs/ffs/ffs_vfsops.c                                          |      6 +-
 head/sys/ufs/ffs/ffs_vnops.c                                           |     25 +-
 head/sys/ufs/ufs/ufs_extattr.c                                         |     44 +-
 head/sys/ufs/ufs/ufs_inode.c                                           |     10 +-
 head/sys/ufs/ufs/ufs_lookup.c                                          |      4 +-
 head/sys/ufs/ufs/ufs_vnops.c                                           |     27 +-
 head/sys/ufs/ufs/ufsmount.h                                            |      6 +-
 head/sys/vm/device_pager.c                                             |     57 +-
 head/sys/vm/memguard.c                                                 |     28 +-
 head/sys/vm/memguard.h                                                 |      4 +-
 head/sys/vm/pmap.h                                                     |      5 +-
 head/sys/vm/swap_pager.c                                               |      4 +-
 head/sys/vm/uma_core.c                                                 |     10 +-
 head/sys/vm/vm.h                                                       |      4 +-
 head/sys/vm/vm_contig.c                                                |    351 -
 head/sys/vm/vm_fault.c                                                 |    169 +-
 head/sys/vm/vm_kern.c                                                  |    144 +-
 head/sys/vm/vm_map.c                                                   |     19 +-
 head/sys/vm/vm_map.h                                                   |     17 +-
 head/sys/vm/vm_mmap.c                                                  |      8 +-
 head/sys/vm/vm_object.c                                                |     11 +-
 head/sys/vm/vm_object.h                                                |     17 +-
 head/sys/vm/vm_page.c                                                  |     90 +-
 head/sys/vm/vm_page.h                                                  |     57 +-
 head/sys/vm/vm_pageout.c                                               |    236 +-
 head/sys/vm/vm_pageout.h                                               |      6 +-
 head/sys/vm/vm_pager.c                                                 |     18 +-
 head/sys/vm/vm_pager.h                                                 |      3 +-
 head/sys/vm/vm_phys.c                                                  |    119 +-
 head/sys/vm/vm_phys.h                                                  |      6 +-
 head/sys/vm/vm_reserv.c                                                |      4 +-
 head/sys/vm/vnode_pager.c                                              |      6 +-
 454 files changed, 55199 insertions(+), 11136 deletions(-)

diffs (85172 lines):

diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/Makefile.sparc64
--- a/head/sys/boot/Makefile.sparc64	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/Makefile.sparc64	Wed Jul 25 16:45:04 2012 +0300
@@ -1,3 +1,4 @@
-# $FreeBSD$
+# $FreeBSD: head/sys/boot/Makefile.sparc64 235364 2012-05-12 20:27:33Z avg $
 
 SUBDIR+=		ofw
+SUBDIR+=		zfs
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/arm/at91/boot0spi/main.c
--- a/head/sys/boot/arm/at91/boot0spi/main.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/arm/at91/boot0spi/main.c	Wed Jul 25 16:45:04 2012 +0300
@@ -21,7 +21,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/boot/arm/at91/boot0spi/main.c 238188 2012-07-07 04:55:42Z imp $
  */
 
 #include "at91rm9200.h"
@@ -29,31 +29,26 @@
 #include "at91rm9200_lowlevel.h"
 #include "spi_flash.h"
 
-#define LOADER_OFFSET 0
-#define FPGA_OFFSET  (15 * FLASH_PAGE_SIZE)
-#define OFFSET FPGA_OFFSET
+#define OFFSET 0
 
-int
+void
 main(void)
 {
 	int len, i, j, off, sec;
 	char *addr = (char *)SDRAM_BASE + (1 << 20); /* download at + 1MB */
 	char *addr2 = (char *)SDRAM_BASE + (2 << 20); /* readback to + 2MB */
-	char *addr3 = (char *)SDRAM_BASE + (3 << 20); /* extra copy at + 3MB */
 
 	SPI_InitFlash();
 	printf("Waiting for data\n");
 	while ((len = xmodem_rx(addr)) == -1)
 		continue;
-	// Need extra copy at addr3
-	memcpy(addr3, addr, (len + FLASH_PAGE_SIZE - 1) / FLASH_PAGE_SIZE * FLASH_PAGE_SIZE);
-	printf("Writing %u bytes to flash at %u\n", len, OFFSET);
+	printf("Writing %u bytes at %u\n", len, OFFSET);
 	for (i = 0; i < len; i+= FLASH_PAGE_SIZE) {
+		off = i + OFFSET;
 		for (j = 0; j < 10; j++) {
-			off = i + OFFSET;
 			SPI_WriteFlash(off, addr + i, FLASH_PAGE_SIZE);
 			SPI_ReadFlash(off, addr2 + i, FLASH_PAGE_SIZE);
-			if (p_memcmp(addr3 + i, addr2 + i, FLASH_PAGE_SIZE) == 0)
+			if (p_memcmp(addr + i, addr2 + i, FLASH_PAGE_SIZE) == 0)
 				break;
 		}
 		if (j >= 10)
@@ -64,5 +59,4 @@
 	    continue;
 	printf("Done\n");
 	reset();
-	return (1);
 }
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/arm/at91/boot2/boot2.c
--- a/head/sys/boot/arm/at91/boot2/boot2.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/arm/at91/boot2/boot2.c	Wed Jul 25 16:45:04 2012 +0300
@@ -16,7 +16,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/boot/arm/at91/boot2/boot2.c 226506 2011-10-18 09:46:52Z des $");
+__FBSDID("$FreeBSD: head/sys/boot/arm/at91/boot2/boot2.c 235988 2012-05-25 09:36:39Z gleb $");
 
 #include <sys/param.h>
 #include <sys/disklabel.h>
@@ -86,15 +86,15 @@
 	RBX_VERBOSE
 };
 
+unsigned board_id; /* board type to pass to kernel, if set by board_* code */
 unsigned dsk_start;
 static char cmd[512];
 static char kname[1024];
 static uint32_t opts;
-static int dsk_meta;
+static uint8_t dsk_meta;
 
 static void load(void);
 static int parse(void);
-static int xfsread(ino_t, void *, size_t);
 static int dskread(void *, unsigned, unsigned);
 #ifdef FIXUP_BOOT_DRV
 static void fixup_boot_drv(caddr_t, int, int, int);
@@ -110,7 +110,7 @@
 #endif
 
 static inline int
-xfsread(ino_t inode, void *buf, size_t nbyte)
+xfsread(ufs_ino_t inode, void *buf, size_t nbyte)
 {
 	if ((size_t)fsread(inode, buf, nbyte) != nbyte)
 		return -1;
@@ -153,7 +153,7 @@
 main(void)
 {
 	int autoboot, c = 0;
-	ino_t ino;
+	ufs_ino_t ino;
 
 	dmadat = (void *)(0x20000000 + (16 << 20));
 	board_init();
@@ -198,7 +198,7 @@
 	Elf32_Ehdr eh;
 	static Elf32_Phdr ep[2];
 	caddr_t p;
-	ino_t ino;
+	ufs_ino_t ino;
 	uint32_t addr;
 	int i, j;
 #ifdef FIXUP_BOOT_DRV
@@ -241,7 +241,7 @@
 #ifdef FIXUP_BOOT_DRV
 	fixup_boot_drv(staddr, klen, bootslice, bootpart);
 #endif
-	((void(*)(int))addr)(opts & RBX_MASK);
+	((void(*)(int, int, int, int))addr)(opts & RBX_MASK, board_id, 0, 0);
 }
 
 static int
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/arm/at91/bootspi/ee.c
--- a/head/sys/boot/arm/at91/bootspi/ee.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/arm/at91/bootspi/ee.c	Wed Jul 25 16:45:04 2012 +0300
@@ -18,7 +18,7 @@
  * only.
  * END_BLOCK
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/boot/arm/at91/bootspi/ee.c 238463 2012-07-15 05:35:14Z imp $
  *****************************************************************************/
 
 #include "at91rm9200_lowlevel.h"
@@ -59,11 +59,11 @@
 	AT91PS_PIO pPio = (AT91PS_PIO)AT91C_BASE_PIOA;
 	AT91PS_PMC pPMC = (AT91PS_PMC)AT91C_BASE_PMC;
 
-	pPio->PIO_ASR = AT91C_PA25_TWD | AT91C_PA26_TWCK;
-	pPio->PIO_PDR = AT91C_PA25_TWD | AT91C_PA26_TWCK;
+	pPio->PIO_ASR = AT91C_PIO_PA25 | AT91C_PIO_PA26;
+	pPio->PIO_PDR = AT91C_PIO_PA25 | AT91C_PIO_PA26;
 
-	pPio->PIO_MDDR = ~AT91C_PA25_TWD;
-	pPio->PIO_MDER = AT91C_PA25_TWD;
+	pPio->PIO_MDDR = ~AT91C_PIO_PA25;
+	pPio->PIO_MDER = AT91C_PIO_PA25;
 
 	pPMC->PMC_PCER = 1u << AT91C_ID_TWI;
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/arm/at91/libat91/Makefile
--- a/head/sys/boot/arm/at91/libat91/Makefile	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/arm/at91/libat91/Makefile	Wed Jul 25 16:45:04 2012 +0300
@@ -1,10 +1,12 @@
-#  $FreeBSD$
+#  $FreeBSD: head/sys/boot/arm/at91/libat91/Makefile 238187 2012-07-07 04:51:59Z imp $
 
 .include "${.CURDIR}/../Makefile.inc"
 
+SOC?=at91rm9200
+
 LIB=		at91
 INTERNALLIB=
-SRCS=at91rm9200_lowlevel.c delay.c eeprom.c emac.c emac_init.c getc.c \
+SRCS=${SOC}_lowlevel.c delay.c eeprom.c emac.c emac_init.c getc.c \
 	putchar.c printf.c reset.c spi_flash.c xmodem.c \
 	sd-card.c strcvt.c strlen.c strcmp.c memcpy.c strcpy.c \
 	memset.c memcmp.c
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/arm/at91/libat91/at91rm9200.h
--- a/head/sys/boot/arm/at91/libat91/at91rm9200.h	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/arm/at91/libat91/at91rm9200.h	Wed Jul 25 16:45:04 2012 +0300
@@ -7,7 +7,7 @@
 //  fitness for any particular purpose, or against the infringements of
 //  intellectual property rights of others.
 // ----------------------------------------------------------------------------
-// $FreeBSD$
+// $FreeBSD: head/sys/boot/arm/at91/libat91/at91rm9200.h 238463 2012-07-15 05:35:14Z imp $
 //
 // File Name           : AT91RM9200.h
 // Object              : AT91RM9200 definitions
@@ -41,6 +41,8 @@
 #ifndef AT91RM9200_H
 #define	AT91RM9200_H
 
+#define ATMEL_ENV
+
 typedef volatile unsigned int AT91_REG;// Hardware register definition
 
 // *****************************************************************************
@@ -2309,7 +2311,7 @@
 // ========== Register definition for BFC peripheral ========== 
 #define	AT91C_BFC_MR    ((AT91_REG *) 	0xFFFFFFC0) // (BFC) BFC Mode Register
 
-#include <at91/at91_pio_rm9200.h>
+#include <at91/at91_pioreg.h>
 
 // *****************************************************************************
 //               PERIPHERAL ID DEFINITIONS FOR AT91RM9200
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/arm/at91/libat91/at91rm9200_lowlevel.c
--- a/head/sys/boot/arm/at91/libat91/at91rm9200_lowlevel.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/arm/at91/libat91/at91rm9200_lowlevel.c	Wed Jul 25 16:45:04 2012 +0300
@@ -24,7 +24,7 @@
  * This software is derived from software provide by Kwikbyte who specifically
  * disclaimed copyright on the code.
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/boot/arm/at91/libat91/at91rm9200_lowlevel.c 238463 2012-07-15 05:35:14Z imp $
  */
 
 #include "at91rm9200.h"
@@ -188,8 +188,8 @@
 	AT91C_BASE_PIOC->PIO_PDR = 0xffff0000;
 #endif
 	// Configure DBGU -use local routine optimized for space
-	AT91C_BASE_PIOA->PIO_ASR = AT91C_PA31_DTXD | AT91C_PA30_DRXD;
-	AT91C_BASE_PIOA->PIO_PDR = AT91C_PA31_DTXD | AT91C_PA30_DRXD;
+	AT91C_BASE_PIOA->PIO_ASR = AT91C_PIO_PA31 | AT91C_PIO_PA30;
+	AT91C_BASE_PIOA->PIO_PDR = AT91C_PIO_PA31 | AT91C_PIO_PA30;
 	pUSART->US_IDR = (unsigned int) -1;
 	pUSART->US_CR =
 	    AT91C_US_RSTRX | AT91C_US_RSTTX | AT91C_US_RXDIS | AT91C_US_TXDIS;
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/arm/at91/libat91/eeprom.c
--- a/head/sys/boot/arm/at91/libat91/eeprom.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/arm/at91/libat91/eeprom.c	Wed Jul 25 16:45:04 2012 +0300
@@ -18,7 +18,7 @@
  * only.
  * END_BLOCK
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/boot/arm/at91/libat91/eeprom.c 238463 2012-07-15 05:35:14Z imp $
  *****************************************************************************/
 
 #include "at91rm9200_lowlevel.h"
@@ -58,11 +58,11 @@
 	AT91PS_PIO pPio = (AT91PS_PIO)AT91C_BASE_PIOA;
 	AT91PS_PMC pPMC = (AT91PS_PMC)AT91C_BASE_PMC;
 
-	pPio->PIO_ASR = AT91C_PA25_TWD | AT91C_PA26_TWCK;
-	pPio->PIO_PDR = AT91C_PA25_TWD | AT91C_PA26_TWCK;
+	pPio->PIO_ASR = AT91C_PIO_PA25 | AT91C_PIO_PA26;
+	pPio->PIO_PDR = AT91C_PIO_PA25 | AT91C_PIO_PA26;
 
-	pPio->PIO_MDDR = ~AT91C_PA25_TWD;
-	pPio->PIO_MDER = AT91C_PA25_TWD;
+	pPio->PIO_MDDR = ~AT91C_PIO_PA25;
+	pPio->PIO_MDER = AT91C_PIO_PA25;
 
 	pPMC->PMC_PCER = 1u << AT91C_ID_TWI;
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/arm/at91/libat91/emac_init.c
--- a/head/sys/boot/arm/at91/libat91/emac_init.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/arm/at91/libat91/emac_init.c	Wed Jul 25 16:45:04 2012 +0300
@@ -24,7 +24,7 @@
  * This software is derived from software provide by Kwikbyte who specifically
  * disclaimed copyright on the code.
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/boot/arm/at91/libat91/emac_init.c 238463 2012-07-15 05:35:14Z imp $
  */
 
 /******************************************************************************
@@ -85,24 +85,24 @@
 
 	AT91C_BASE_PMC->PMC_PCER = 1u << AT91C_ID_EMAC;
 	AT91C_BASE_PIOA->PIO_ASR = 
-	  AT91C_PA14_ERXER | AT91C_PA12_ERX0 | AT91C_PA13_ERX1 |
-	  AT91C_PA8_ETXEN | AT91C_PA16_EMDIO | AT91C_PA9_ETX0 |
-	  AT91C_PA10_ETX1 | AT91C_PA11_ECRS_ECRSDV | AT91C_PA15_EMDC |
-	  AT91C_PA7_ETXCK_EREFCK;
+	  AT91C_PIO_PA14 | AT91C_PIO_PA12 | AT91C_PIO_PA13 |
+	  AT91C_PIO_PA8 | AT91C_PIO_PA16 | AT91C_PIO_PA9 |
+	  AT91C_PIO_PA10 | AT91C_PIO_PA11 | AT91C_PIO_PA15 |
+	  AT91C_PIO_PA7;
 	AT91C_BASE_PIOA->PIO_PDR = 
-	  AT91C_PA14_ERXER | AT91C_PA12_ERX0 | AT91C_PA13_ERX1 |
-	  AT91C_PA8_ETXEN | AT91C_PA16_EMDIO | AT91C_PA9_ETX0 |
-	  AT91C_PA10_ETX1 | AT91C_PA11_ECRS_ECRSDV | AT91C_PA15_EMDC |
-	  AT91C_PA7_ETXCK_EREFCK;
+	  AT91C_PIO_PA14 | AT91C_PIO_PA12 | AT91C_PIO_PA13 |
+	  AT91C_PIO_PA8 | AT91C_PIO_PA16 | AT91C_PIO_PA9 |
+	  AT91C_PIO_PA10 | AT91C_PIO_PA11 | AT91C_PIO_PA15 |
+	  AT91C_PIO_PA7;
 #if defined(BOOT_KB920X) | defined(BOOT_BWCT)	/* Really !RMII */
 	AT91C_BASE_PIOB->PIO_BSR =
-	  AT91C_PB12_ETX2 | AT91C_PB13_ETX3 | AT91C_PB14_ETXER |
-	  AT91C_PB15_ERX2 | AT91C_PB16_ERX3 | AT91C_PB17_ERXDV |
-	  AT91C_PB18_ECOL | AT91C_PB19_ERXCK;
+	  AT91C_PIO_PB12 | AT91C_PIO_PB13 | AT91C_PIO_PB14 |
+	  AT91C_PIO_PB15 | AT91C_PIO_PB16 | AT91C_PIO_PB17 |
+	  AT91C_PIO_PB18 | AT91C_PIO_PB19;
 	AT91C_BASE_PIOB->PIO_PDR =
-	  AT91C_PB12_ETX2 | AT91C_PB13_ETX3 | AT91C_PB14_ETXER |
-	  AT91C_PB15_ERX2 | AT91C_PB16_ERX3 | AT91C_PB17_ERXDV |
-	  AT91C_PB18_ECOL | AT91C_PB19_ERXCK;
+	  AT91C_PIO_PB12 | AT91C_PIO_PB13 | AT91C_PIO_PB14 |
+	  AT91C_PIO_PB15 | AT91C_PIO_PB16 | AT91C_PIO_PB17 |
+	  AT91C_PIO_PB18 | AT91C_PIO_PB19;
 #endif
 	pEmac->EMAC_CTL  = 0;
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/arm/at91/libat91/lib_AT91RM9200.h
--- a/head/sys/boot/arm/at91/libat91/lib_AT91RM9200.h	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/arm/at91/libat91/lib_AT91RM9200.h	Wed Jul 25 16:45:04 2012 +0300
@@ -24,7 +24,7 @@
  * This software is derived from software provide by Kwikbyte who specifically
  * disclaimed copyright on the code.
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/boot/arm/at91/libat91/lib_AT91RM9200.h 238463 2012-07-15 05:35:14Z imp $
  */
 
 #ifndef __LIBAT91RM9200_H
@@ -134,17 +134,17 @@
 	// Configure PIO controllers to periph mode
 	AT91F_PIO_CfgPeriph(
 		AT91C_BASE_PIOA, // PIO controller base address
-		((unsigned int) AT91C_PA28_MCCDA   ) |
-		((unsigned int) AT91C_PA29_MCDA0   ) |
-		((unsigned int) AT91C_PA27_MCCK    ), // Peripheral A
+		((unsigned int) AT91C_PIO_PA28   ) |
+		((unsigned int) AT91C_PIO_PA29   ) |
+		((unsigned int) AT91C_PIO_PA27    ), // Peripheral A
 		0); // Peripheral B
 	// Configure PIO controllers to periph mode
 	AT91F_PIO_CfgPeriph(
 		AT91C_BASE_PIOB, // PIO controller base address
 		0, // Peripheral A
-		((unsigned int) AT91C_PB5_MCDA3   ) |
-		((unsigned int) AT91C_PB3_MCDA1   ) |
-		((unsigned int) AT91C_PB4_MCDA2   )); // Peripheral B
+		((unsigned int) AT91C_PIO_PB5   ) |
+		((unsigned int) AT91C_PIO_PB3   ) |
+		((unsigned int) AT91C_PIO_PB4   )); // Peripheral B
 }
 
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/arm/at91/libat91/spi_flash.c
--- a/head/sys/boot/arm/at91/libat91/spi_flash.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/arm/at91/libat91/spi_flash.c	Wed Jul 25 16:45:04 2012 +0300
@@ -19,7 +19,7 @@
  * only.
  * END_BLOCK
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/boot/arm/at91/libat91/spi_flash.c 238463 2012-07-15 05:35:14Z imp $
  *****************************************************************************/
 
 #include "at91rm9200.h"
@@ -223,10 +223,10 @@
 
 	// enable CS0, CLK, MOSI, MISO
 	pPio = (AT91PS_PIO)AT91C_BASE_PIOA;
-	pPio->PIO_ASR = AT91C_PA3_NPCS0 | AT91C_PA1_MOSI | AT91C_PA0_MISO |
-	    AT91C_PA2_SPCK;
-	pPio->PIO_PDR = AT91C_PA3_NPCS0 | AT91C_PA1_MOSI | AT91C_PA0_MISO |
-	    AT91C_PA2_SPCK;
+	pPio->PIO_ASR = AT91C_PIO_PA3 | AT91C_PIO_PA1 | AT91C_PIO_PA0 |
+	    AT91C_PIO_PA2;
+	pPio->PIO_PDR = AT91C_PIO_PA3 | AT91C_PIO_PA1 | AT91C_PIO_PA0 |
+	    AT91C_PIO_PA2;
 
 	// enable clocks to SPI
 	AT91C_BASE_PMC->PMC_PCER = 1u << AT91C_ID_SPI;
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/arm/at91/linker.cfg
--- a/head/sys/boot/arm/at91/linker.cfg	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/arm/at91/linker.cfg	Wed Jul 25 16:45:04 2012 +0300
@@ -18,7 +18,7 @@
  * only.
  * END_BLOCK
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/boot/arm/at91/linker.cfg 238186 2012-07-07 04:49:53Z imp $
  ******************************************************************************/
 OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm",
 	      "elf32-littlearm")
@@ -31,258 +31,26 @@
   .text      :
   {
     *(.text)
-    *(.text.*)
-    *(.stub)
-    /* .gnu.warning sections are handled specially by elf32.em.  */
-    *(.gnu.warning)
-    *(.gnu.linkonce.t.*)
-    *(.glue_7t) *(.glue_7)
   }
-  .interp     : { *(.interp) 	}
-  .hash          : { *(.hash)		}
-  .dynsym        : { *(.dynsym)		}
-  .dynstr        : { *(.dynstr)		}
-  .gnu.version   : { *(.gnu.version)	}
-  .gnu.version_d   : { *(.gnu.version_d)	}
-  .gnu.version_r   : { *(.gnu.version_r)	}
-  .rel.init      : { *(.rel.init)	}
-  .rela.init     : { *(.rela.init)	}
-  .rel.text      :
-    {
-      *(.rel.text)
-      *(.rel.text.*)
-      *(.rel.gnu.linkonce.t.*)
-    }
-  .rela.text     :
-    {
-      *(.rela.text)
-      *(.rela.text.*)
-      *(.rela.gnu.linkonce.t.*)
-    }
-  .rel.fini      : { *(.rel.fini)	}
-  .rela.fini     : { *(.rela.fini)	}
-  .rel.rodata    :
-    {
-      *(.rel.rodata)
-      *(.rel.rodata.*)
-      *(.rel.gnu.linkonce.r.*)
-    }
-  .rela.rodata   :
-    {
-      *(.rela.rodata)
-      *(.rela.rodata.*)
-      *(.rela.gnu.linkonce.r.*)
-    }
-  .rel.data      :
-    {
-      *(.rel.data)
-      *(.rel.data.*)
-      *(.rel.gnu.linkonce.d.*)
-    }
-  .rela.data     :
-    {
-      *(.rela.data)
-      *(.rela.data.*)
-      *(.rela.gnu.linkonce.d.*)
-    }
-  .rel.ctors     : { *(.rel.ctors)	}
-  .rela.ctors    : { *(.rela.ctors)	}
-  .rel.dtors     : { *(.rel.dtors)	}
-  .rela.dtors    : { *(.rela.dtors)	}
-  .rel.got       : { *(.rel.got)		}
-  .rela.got      : { *(.rela.got)		}
-  .rel.sdata     :
-    {
-      *(.rel.sdata)
-      *(.rel.sdata.*)
-      *(.rel.gnu.linkonce.s.*)
-    }
-  .rela.sdata     :
-    {
-      *(.rela.sdata)
-      *(.rela.sdata.*)
-      *(.rela.gnu.linkonce.s.*)
-    }
-  .rel.sbss      :
-    { 
-      *(.rel.sbss)
-      *(.rel.sbss.*)
-      *(.rel.gnu.linkonce.sb.*)
-    }
-  .rela.sbss     :
-    {
-      *(.rela.sbss)
-      *(.rela.sbss.*)
-      *(.rel.gnu.linkonce.sb.*)
-    }
-  .rel.sdata2    : 
-    { 
-      *(.rel.sdata2)
-      *(.rel.sdata2.*)
-      *(.rel.gnu.linkonce.s2.*)
-    }
-  .rela.sdata2   : 
-    {
-      *(.rela.sdata2)
-      *(.rela.sdata2.*)
-      *(.rela.gnu.linkonce.s2.*)
-    }
-  .rel.sbss2     : 
-    { 
-      *(.rel.sbss2)	
-      *(.rel.sbss2.*)
-      *(.rel.gnu.linkonce.sb2.*)
-    }
-  .rela.sbss2    : 
-    { 
-      *(.rela.sbss2)	
-      *(.rela.sbss2.*)
-      *(.rela.gnu.linkonce.sb2.*)
-    }
-  .rel.bss       : 
-    { 
-      *(.rel.bss)
-      *(.rel.bss.*)
-      *(.rel.gnu.linkonce.b.*)
-    }
-  .rela.bss      : 
-    { 
-      *(.rela.bss)
-      *(.rela.bss.*)
-      *(.rela.gnu.linkonce.b.*)
-    }
-  .rel.plt       : { *(.rel.plt)		}
-  .rela.plt      : { *(.rela.plt)		}
-  .init          : 
-  { 
-    KEEP (*(.init))
-  } =0
-  .plt      : { *(.plt)	}
-  .fini      :
-  {
-    KEEP (*(.fini))
-  } =0
   PROVIDE (__etext = .);
   PROVIDE (_etext = .);
   PROVIDE (etext = .);
-  .rodata   : { *(.rodata) *(.rodata.*) *(.gnu.linkonce.r.*) }
-  .rodata1   : { *(.rodata1) }
-  .sdata2   : { *(.sdata2) *(.sdata2.*) *(.gnu.linkonce.s2.*) }
-  .sbss2   : { *(.sbss2) *(.sbss2.*) *(.gnu.linkonce.sb2.*) }
   .data    :
   {
     __data_start = . ;
     *(.data)
-    *(.data.*)
-    *(.gnu.linkonce.d.*)
-    SORT(CONSTRUCTORS)
-  }
-  .data1   : { *(.data1) }
-  . = 0x21200000;
-  .eh_frame : { KEEP (*(.eh_frame)) }
-  .gcc_except_table : { *(.gcc_except_table) }
-  .ctors   : 
-  {
-    /* gcc uses crtbegin.o to find the start of
-       the constructors, so we make sure it is
-       first.  Because this is a wildcard, it
-       doesn't matter if the user does not
-       actually link against crtbegin.o; the
-       linker won't look for a file to match a
-       wildcard.  The wildcard also means that it
-       doesn't matter which directory crtbegin.o
-       is in.  */
-    KEEP (*crtbegin.o(.ctors))
-    /* We don't want to include the .ctor section from
-       from the crtend.o file until after the sorted ctors.
-       The .ctor section from the crtend file contains the
-       end of ctors marker and it must be last */
-    KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
-    KEEP (*(SORT(.ctors.*)))
-    KEEP (*(.ctors))
-  }
-   .dtors         :
-  {
-    KEEP (*crtbegin.o(.dtors))
-    KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
-    KEEP (*(SORT(.dtors.*)))
-    KEEP (*(.dtors))
-  }
-  .got		  : { *(.got.plt) *(.got) }
-  .dynamic       : { *(.dynamic) }
-  /* We want the small data sections together, so single-instruction offsets
-     can access them all, and initialized data all before uninitialized, so
-     we can shorten the on-disk segment size.  */
-  .sdata     : 
-  {
-    *(.sdata) 
-    *(.sdata.*)
-    *(.gnu.linkonce.s.*)
   }
   _edata = .;
   PROVIDE (edata = .);
   __bss_start = .;
   __bss_start__ = .;
-  .sbss      :
-  {
-    PROVIDE (__sbss_start = .);
-    PROVIDE (___sbss_start = .);
-    *(.dynsbss)
-    *(.sbss)
-    *(.sbss.*)
-    *(.gnu.linkonce.sb.*)
-    *(.scommon)
-    PROVIDE (__sbss_end = .);
-    PROVIDE (___sbss_end = .);
-  }
   .bss       :
   {
-   *(.dynbss)
    *(.bss)
-   *(.bss.*)
-   *(.gnu.linkonce.b.*)
-   *(COMMON)
-   /* Align here to ensure that the .bss section occupies space up to
-      _end.  Align after .bss to ensure correct alignment even if the
-      .bss section disappears because there are no input sections.  */
    . = ALIGN(32 / 8);
   }
   . = ALIGN(32 / 8);
   _end = .;
   _bss_end__ = . ; __bss_end__ = . ; __end__ = . ;
   PROVIDE (end = .);
-  /* Stabs debugging sections.  */
-  .stab 0 : { *(.stab) }
-  .stabstr 0 : { *(.stabstr) }
-  .stab.excl 0 : { *(.stab.excl) }
-  .stab.exclstr 0 : { *(.stab.exclstr) }
-  .stab.index 0 : { *(.stab.index) }
-  .stab.indexstr 0 : { *(.stab.indexstr) }
-  .comment 0 : { *(.comment) }
-  /* DWARF debug sections.
-     Symbols in the DWARF debugging sections are relative to the beginning
-     of the section so we begin them at 0.  */
-  /* DWARF 1 */
-  .debug          0 : { *(.debug) }
-  .line           0 : { *(.line) }
-  /* GNU DWARF 1 extensions */
-  .debug_srcinfo  0 : { *(.debug_srcinfo) }
-  .debug_sfnames  0 : { *(.debug_sfnames) }
-  /* DWARF 1.1 and DWARF 2 */
-  .debug_aranges  0 : { *(.debug_aranges) }
-  .debug_pubnames 0 : { *(.debug_pubnames) }
-  /* DWARF 2 */
-  .debug_info     0 : { *(.debug_info) *(.gnu.linkonce.wi.*) }
-  .debug_abbrev   0 : { *(.debug_abbrev) }
-  .debug_line     0 : { *(.debug_line) }
-  .debug_frame    0 : { *(.debug_frame) }
-  .debug_str      0 : { *(.debug_str) }
-  .debug_loc      0 : { *(.debug_loc) }
-  .debug_macinfo  0 : { *(.debug_macinfo) }
-  /* SGI/MIPS DWARF 2 extensions */
-  .debug_weaknames 0 : { *(.debug_weaknames) }
-  .debug_funcnames 0 : { *(.debug_funcnames) }
-  .debug_typenames 0 : { *(.debug_typenames) }
-  .debug_varnames  0 : { *(.debug_varnames) }
-  /* These must appear regardless of  .  */
 }
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/arm/ixp425/boot2/boot2.c
--- a/head/sys/boot/arm/ixp425/boot2/boot2.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/arm/ixp425/boot2/boot2.c	Wed Jul 25 16:45:04 2012 +0300
@@ -15,7 +15,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/boot/arm/ixp425/boot2/boot2.c 226506 2011-10-18 09:46:52Z des $");
+__FBSDID("$FreeBSD: head/sys/boot/arm/ixp425/boot2/boot2.c 235988 2012-05-25 09:36:39Z gleb $");
 
 #include <sys/param.h>
 #include <sys/disklabel.h>
@@ -98,7 +98,6 @@
 
 static void load(void);
 static int parse(void);
-static int xfsread(ino_t, void *, size_t);
 static int dskread(void *, unsigned, unsigned);
 static int drvread(void *, unsigned, unsigned);
 #ifdef FIXUP_BOOT_DRV
@@ -114,7 +113,7 @@
 #endif
 
 static inline int
-xfsread(ino_t inode, void *buf, size_t nbyte)
+xfsread(ufs_ino_t inode, void *buf, size_t nbyte)
 {
 	if ((size_t)fsread(inode, buf, nbyte) != nbyte)
 		return -1;
@@ -158,7 +157,7 @@
 {
 	const char *bt;
 	int autoboot, c = 0;
-	ino_t ino;
+	ufs_ino_t ino;
 
 	dmadat = (void *)(0x1c0000);
 	p_memset((char *)dmadat, 0, 32 * 1024);
@@ -207,7 +206,7 @@
 	Elf32_Ehdr eh;
 	static Elf32_Phdr ep[2];
 	caddr_t p;
-	ino_t ino;
+	ufs_ino_t ino;
 	uint32_t addr;
 	int i, j;
 #ifdef FIXUP_BOOT_DRV
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/arm/uboot/Makefile
--- a/head/sys/boot/arm/uboot/Makefile	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/arm/uboot/Makefile	Wed Jul 25 16:45:04 2012 +0300
@@ -1,4 +1,4 @@
-# $FreeBSD$
+# $FreeBSD: head/sys/boot/arm/uboot/Makefile 236159 2012-05-27 16:27:04Z kientzle $
 
 .include <bsd.own.mk>
 
@@ -7,6 +7,9 @@
 BINDIR?=	/boot
 INSTALLFLAGS=	-b
 WARNS?=		1
+# Address at which ubldr will be loaded.
+# This varies for different boards and SOCs.
+UBLDR_LOADADDR?=	0x1000000
 
 # Architecture-specific loader code
 SRCS=		start.S conf.c vers.c
@@ -15,6 +18,11 @@
 LOADER_UFS_SUPPORT?=	yes
 LOADER_CD9660_SUPPORT?=	no
 LOADER_EXT2FS_SUPPORT?=	no
+.if ${MK_NAND} != "no"
+LOADER_NANDFS_SUPPORT?= yes
+.else
+LOADER_NANDFS_SUPPORT?= no
+.endif
 LOADER_NET_SUPPORT?=	yes
 LOADER_NFS_SUPPORT?=	yes
 LOADER_TFTP_SUPPORT?=	no
@@ -38,6 +46,9 @@
 .if ${LOADER_EXT2FS_SUPPORT} == "yes"
 CFLAGS+=	-DLOADER_EXT2FS_SUPPORT
 .endif
+.if ${LOADER_NANDFS_SUPPORT} == "yes"
+CFLAGS+=	-DLOADER_NANDFS_SUPPORT
+.endif
 .if ${LOADER_GZIP_SUPPORT} == "yes"
 CFLAGS+=	-DLOADER_GZIP_SUPPORT
 .endif
@@ -77,7 +88,9 @@
 
 CFLAGS+=	-ffreestanding
 
-LDFLAGS=	-nostdlib -static -T ${.CURDIR}/ldscript.${MACHINE_CPUARCH}
+LDFLAGS=	-nostdlib -static
+LDFLAGS+=	-T ldscript.generated
+LDFLAGS+=	-T ${.CURDIR}/ldscript.${MACHINE_CPUARCH}
 
 # Pull in common loader code
 .PATH:		${.CURDIR}/../../uboot/common
@@ -102,6 +115,18 @@
 	cat ${.ALLSRC} | \
 	    awk -f ${.CURDIR}/../../common/merge_help.awk > ${.TARGET}
 
+${PROG}: ldscript.generated ${.CURDIR}/ldscript.${MACHINE_CPUARCH}
+
+ldscript.generated::
+	rm -f ldscript.generated.tmp
+	echo "UBLDR_LOADADDR = ${UBLDR_LOADADDR};" >ldscript.generated.tmp
+	if diff ldscript.generated ldscript.generated.tmp > /dev/null; then \
+		true; \
+	else \
+		rm -f ldscript.generated; \
+		mv ldscript.generated.tmp ldscript.generated; \
+	fi
+
 .PATH: ${.CURDIR}/../../forth
 FILES=	loader.help
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/arm/uboot/conf.c
--- a/head/sys/boot/arm/uboot/conf.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/arm/uboot/conf.c	Wed Jul 25 16:45:04 2012 +0300
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/boot/arm/uboot/conf.c 235537 2012-05-17 10:11:18Z gber $");
 
 #include <stand.h>
 #include "bootstrap.h"
@@ -56,6 +56,9 @@
 #if defined(LOADER_EXT2FS_SUPPORT)
 	&ext2fs_fsops,
 #endif
+#if defined(LOADER_NANDFS_SUPPORT)
+	&nandfs_fsops,
+#endif
 #if defined(LOADER_NFS_SUPPORT)
 	&nfs_fsops,
 #endif
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/arm/uboot/ldscript.arm
--- a/head/sys/boot/arm/uboot/ldscript.arm	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/arm/uboot/ldscript.arm	Wed Jul 25 16:45:04 2012 +0300
@@ -1,11 +1,11 @@
-/* $FreeBSD$ */
+/* $FreeBSD: head/sys/boot/arm/uboot/ldscript.arm 236159 2012-05-27 16:27:04Z kientzle $ */
 
 OUTPUT_ARCH(arm)
 ENTRY(_start)
 SECTIONS
 {
   /* Read-only sections, merged into text segment: */
-  . = 0x1000000 + SIZEOF_HEADERS;
+  . = UBLDR_LOADADDR + SIZEOF_HEADERS;
   .interp     : { *(.interp) 	}
   .hash          : { *(.hash)		}
   .dynsym        : { *(.dynsym)		}
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/arm/uboot/start.S
--- a/head/sys/boot/arm/uboot/start.S	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/arm/uboot/start.S	Wed Jul 25 16:45:04 2012 +0300
@@ -23,7 +23,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/boot/arm/uboot/start.S 234908 2012-05-02 05:49:58Z kientzle $
  */
 
 #include <machine/asm.h>
@@ -49,27 +49,20 @@
  * syscall()
  */
 ENTRY(syscall)
-	/* Save caller's lr */
+	/* Save caller's lr and r8 */
 	ldr	ip, =saved_regs
 	str	lr, [ip, #4]
-	/* Save loader's r8 */
-	ldr	ip, =saved_regs
 	str	r8, [ip, #8]
-
 	/* Restore U-Boot's r8 */
-	ldr	ip, =saved_regs
 	ldr	r8, [ip, #0]
 	/* Call into U-Boot */
 	ldr	lr, =return_from_syscall
 	ldr	ip, =syscall_ptr
 	ldr	pc, [ip]
-
 return_from_syscall:
-	/* Restore loader's r8 */
+	/* Restore loader's r8 and lr */
 	ldr	ip, =saved_regs
 	ldr	r8, [ip, #8]
-	/* Restore caller's lr */
-	ldr	ip, =saved_regs
 	ldr	lr, [ip, #4]
 	/* Return to caller */
 	mov	pc, lr
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/arm/uboot/version
--- a/head/sys/boot/arm/uboot/version	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/arm/uboot/version	Wed Jul 25 16:45:04 2012 +0300
@@ -1,8 +1,9 @@
-$FreeBSD$
+$FreeBSD: head/sys/boot/arm/uboot/version 235537 2012-05-17 10:11:18Z gber $
 
 NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE.  The format of this
 file is important.  Make sure the current version number is on line 6.
 
+1.2:	Extended with NAND FS support.
 1.1:	Flattened Device Tree blob support.
 1.0:	Added storage support. Booting from HDD, USB, etc. is now possible.
 0.5:	Initial U-Boot/arm version (netbooting only).
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/common/boot.c
--- a/head/sys/boot/common/boot.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/common/boot.c	Wed Jul 25 16:45:04 2012 +0300
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/boot/common/boot.c 235330 2012-05-12 09:07:41Z avg $");
 
 /*
  * Loading modules, booting the system
@@ -311,12 +311,12 @@
     if (getenv("vfs.root.mountfrom") != NULL)
 	return(0);
 
+    error = 1;
     sprintf(lbuf, "%s/etc/fstab", rootdev);
     if ((fd = open(lbuf, O_RDONLY)) < 0)
-	return(1);
+	goto notfound;
 
     /* loop reading lines from /etc/fstab    What was that about sscanf again? */
-    error = 1;
     while (fgetstr(lbuf, sizeof(lbuf), fd) >= 0) {
 	if ((lbuf[0] == 0) || (lbuf[0] == '#'))
 	    continue;
@@ -377,6 +377,20 @@
 	break;
     }
     close(fd);
+
+notfound:
+    if (error) {
+	const char *currdev;
+
+	currdev = getenv("currdev");
+	if (currdev != NULL && strncmp("zfs:", currdev, 4) == 0) {
+	    cp = strdup(currdev);
+	    cp[strlen(cp) - 1] = '\0';
+	    setenv("vfs.root.mountfrom", cp, 0);
+	    error = 0;
+	}
+    }
+
     return(error);
 }
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/common/bootstrap.h
--- a/head/sys/boot/common/bootstrap.h	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/common/bootstrap.h	Wed Jul 25 16:45:04 2012 +0300
@@ -23,9 +23,12 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/sys/boot/common/bootstrap.h 220311 2011-04-03 22:31:51Z marcel $
+ * $FreeBSD: head/sys/boot/common/bootstrap.h 235329 2012-05-12 09:03:30Z avg $
  */
 
+#ifndef _BOOTSTRAP_H_
+#define	_BOOTSTRAP_H_
+
 #include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/linker_set.h>
@@ -314,6 +317,9 @@
 #else
     void	(*arch_loadseg)(void *eh, void *ph, uint64_t delta);
 #endif
+
+    /* Probe ZFS pool(s), if needed. */
+    void	(*arch_zfs_probe)(void);
 };
 extern struct arch_switch archsw;
 
@@ -323,3 +329,11 @@
 void	dev_cleanup(void);
 
 time_t	time(time_t *tloc);
+
+#ifndef CTASSERT                /* Allow lint to override */
+#define CTASSERT(x)             _CTASSERT(x, __LINE__)
+#define _CTASSERT(x, y)         __CTASSERT(x, y)
+#define __CTASSERT(x, y)        typedef char __assert ## y[(x) ? 1 : -1]
+#endif
+
+#endif /* !_BOOTSTRAP_H_ */
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/common/load_elf.c
--- a/head/sys/boot/common/load_elf.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/common/load_elf.c	Wed Jul 25 16:45:04 2012 +0300
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/boot/common/load_elf.c 223695 2011-06-30 16:08:56Z dfr $");
+__FBSDID("$FreeBSD: head/sys/boot/common/load_elf.c 237338 2012-06-20 21:06:51Z jhb $");
 
 #include <sys/param.h>
 #include <sys/exec.h>
@@ -612,7 +612,7 @@
     Elf_Addr v, p, p_stop;
 
     if (__elfN(lookup_symbol)(fp, ef, "__start_set_modmetadata_set", &sym) != 0)
-	return ENOENT;
+	return 0;
     p = sym.st_value + ef->off;
     if (__elfN(lookup_symbol)(fp, ef, "__stop_set_modmetadata_set", &sym) != 0)
 	return ENOENT;
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/common/load_elf_obj.c
--- a/head/sys/boot/common/load_elf_obj.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/common/load_elf_obj.c	Wed Jul 25 16:45:04 2012 +0300
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/boot/common/load_elf_obj.c 223295 2011-06-19 13:35:41Z kan $");
+__FBSDID("$FreeBSD: head/sys/boot/common/load_elf_obj.c 237338 2012-06-20 21:06:51Z jhb $");
 
 #include <sys/param.h>
 #include <sys/exec.h>
@@ -369,7 +369,7 @@
 
 	if (__elfN(obj_lookup_set)(fp, ef, "modmetadata_set", &p, &p_stop,
 	    &modcnt) != 0)
-		return ENOENT;
+		return 0;
 
 	modcnt = 0;
 	while (p < p_stop) {
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/common/loader.8
--- a/head/sys/boot/common/loader.8	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/common/loader.8	Wed Jul 25 16:45:04 2012 +0300
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/sys/boot/common/loader.8 233648 2012-03-29 05:02:12Z eadler $
+.\" $FreeBSD: head/sys/boot/common/loader.8 235873 2012-05-24 02:24:03Z wblock $
 .\"
 .Dd January 7, 2012
 .Dt LOADER 8
@@ -423,7 +423,7 @@
 Defines the base i/o port used to access console UART
 (i386 and amd64 only).
 If the variable is not set, its assumed value is 0x3F8, which
-corresponds to PC port COM1, unless overriden by
+corresponds to PC port COM1, unless overridden by
 .Va BOOT_COMCONSOLE_PORT
 variable during the compilation of
 .Nm .
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/common/ufsread.c
--- a/head/sys/boot/common/ufsread.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/common/ufsread.c	Wed Jul 25 16:45:04 2012 +0300
@@ -44,7 +44,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/boot/common/ufsread.c 233105 2012-03-18 02:19:30Z marius $");
+__FBSDID("$FreeBSD: head/sys/boot/common/ufsread.c 235988 2012-05-25 09:36:39Z gleb $");
 
 #include <ufs/ufs/dinode.h>
 #include <ufs/ufs/dir.h>
@@ -58,6 +58,8 @@
 #define cgbase(fs, c)   ((ufs2_daddr_t)((fs)->fs_fpg * (c)))
 #endif
 
+typedef	uint32_t	ufs_ino_t;
+
 /*
  * We use 4k `virtual' blocks for filesystem data, whatever the actual
  * filesystem block size. FFS blocks are always a multiple of 4k.
@@ -85,14 +87,14 @@
 };
 static struct dmadat *dmadat;
 
-static ino_t lookup(const char *);
-static ssize_t fsread(ino_t, void *, size_t);
+static ufs_ino_t lookup(const char *);
+static ssize_t fsread(ufs_ino_t, void *, size_t);
 
 static uint8_t ls, dsk_meta;
 static uint32_t fs_off;
 
 static __inline uint8_t
-fsfind(const char *name, ino_t * ino)
+fsfind(const char *name, ufs_ino_t * ino)
 {
 	static char buf[DEV_BSIZE];
 	struct direct *d;
@@ -116,12 +118,12 @@
 	return 0;
 }
 
-static ino_t
+static ufs_ino_t
 lookup(const char *path)
 {
 	static char name[MAXNAMLEN + 1];
 	const char *s;
-	ino_t ino;
+	ufs_ino_t ino;
 	ssize_t n;
 	uint8_t dt;
 
@@ -163,7 +165,7 @@
 #endif
 
 static ssize_t
-fsread(ino_t inode, void *buf, size_t nbyte)
+fsread(ufs_ino_t inode, void *buf, size_t nbyte)
 {
 #ifndef UFS2_ONLY
 	static struct ufs1_dinode dp1;
@@ -173,7 +175,7 @@
 	static struct ufs2_dinode dp2;
 #endif
 	static struct fs fs;
-	static ino_t inomap;
+	static ufs_ino_t inomap;
 	char *blkbuf;
 	void *indbuf;
 	char *s;
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/fdt/dts/bindings-localbus.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/boot/fdt/dts/bindings-localbus.txt	Wed Jul 25 16:45:04 2012 +0300
@@ -0,0 +1,83 @@
+$FreeBSD: head/sys/boot/fdt/dts/bindings-localbus.txt 235609 2012-05-18 14:41:14Z gber $
+
+Marvell Device bus (localbus) configuration.
+============================================
+
+1. Properties for localbus nodes
+
+1.1 ranges
+
+Property:	ranges
+
+Value type:	<prop-encoded-array> encoded as arbitrary number of localbus 
+		nodes specifiers.
+		
+Description:	ranges property defines values used for mapping devices 
+		connected to localbus, in Marvell devices it is used also for 
+		setting decoding windows. 
+		
+		a) child node address-cells:
+		   - first cell: number of bank (chip select) 
+		   - second cell: (Marvell devices) Target ID for decoding
+		   	windows setup
+		   	
+		b) parent node address cells:
+		   - address offset: used with parent's node base address to 
+		   	specify base address of mapped device
+		
+		c) child node size-cells:
+		   - size: defines amount of memory that should be reserved for
+			device      
+			
+1.2 bank-count
+
+Property:	bank-count
+
+Value type:	<u32>	
+
+Description:	The bank_count property defines maximum number of banks on
+		localbus node. Bank is most often interpreted as device chip
+		select, but may also describe another device (e.g. SPI flash).  
+		
+1.3 Example
+
+	localbus at 0 {
+		#address-cells = <2>;
+		#size-cells = <1>;
+		compatible = "mrvl,lbc";
+		bank-count = <5>;
+
+		/* This reflects CPU decode windows setup. */
+		ranges = <0x0 0x2f 0xb2200000 0x00100000
+			  0x1 0x3e 0xb2100000 0x00100000
+			  0x2 0x3d 0xb0000000 0x02000000
+			  0x3 0x3b 0xb2000000 0x00100000>;
+	};
+
+2. Properties for localbus consumer nodes:
+
+2.1 reg
+
+Property:	reg
+
+Value type: 	<prop-encoded-array>
+
+Description:	A standard property required for localbus child nodes. Defines 
+		the device memory region.
+		
+		a) first cell: number of bank (chip select)
+		
+		b) address offset: used with address offset from parent's ranges
+			for corresponding bank to specify base address of 
+			the device
+		   	
+		c) size: defines size of the device memory region
+		
+2.2 Example
+
+	nor at 0,0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "cfi-flash";
+		reg = <0x0 0x0 0x00100000>;
+	};
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/fdt/dts/db78100.dts
--- a/head/sys/boot/fdt/dts/db78100.dts	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/fdt/dts/db78100.dts	Wed Jul 25 16:45:04 2012 +0300
@@ -28,7 +28,7 @@
  *
  * Marvell DB-78100 Device Tree Source.
  *
- * $FreeBSD: head/sys/boot/fdt/dts/db78100.dts 232518 2012-03-04 19:22:52Z raj $
+ * $FreeBSD: head/sys/boot/fdt/dts/db78100.dts 235609 2012-05-18 14:41:14Z gber $
  */
 
 /dts-v1/;
@@ -69,25 +69,23 @@
 		reg = <0x0 0x20000000>;		// 512M at 0x0
 	};
 
-	localbus at f1000000 {
+	localbus at 0 {
 		#address-cells = <2>;
 		#size-cells = <1>;
 		compatible = "mrvl,lbc";
-		win-count = <14>;
+		bank-count = <5>;
 
 		/* This reflects CPU decode windows setup. */
-		ranges = <0x0 0x0f 0xf9300000 0x00100000
-			  0x1 0x1e 0xfa000000 0x00100000
-			  0x2 0x1d 0xfa100000 0x02000000
-			  0x3 0x1b 0xfc100000 0x00000400>;
+		ranges = <0x0 0x2f 0xf9300000 0x00100000
+			  0x1 0x3e 0xf9400000 0x00100000
+			  0x2 0x3d 0xf9500000 0x02000000
+			  0x3 0x3b 0xfb500000 0x00100000>;
 
 		nor at 0,0 {
 			#address-cells = <1>;
 			#size-cells = <1>;
 			compatible = "cfi-flash";
 			reg = <0x0 0x0 0x00100000>;
-			bank-width = <2>;
-			device-width = <1>;
 		};
 
 		led at 1,0 {
@@ -102,16 +100,13 @@
 			#size-cells = <1>;
 			compatible = "cfi-flash";
 			reg = <0x2 0x0 0x02000000>;
-			bank-width = <2>;
-			device-width = <1>;
 		};
 
 		nand at 3,0 {
 			#address-cells = <1>;
 			#size-cells = <1>;
+			compatible = "mrvl,nfc";
 			reg = <0x3 0x0 0x00100000>;
-			bank-width = <2>;
-			device-width = <1>;
 		};
 	};
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/fdt/dts/db88f6281.dts
--- a/head/sys/boot/fdt/dts/db88f6281.dts	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/fdt/dts/db88f6281.dts	Wed Jul 25 16:45:04 2012 +0300
@@ -28,7 +28,7 @@
  *
  * Marvell DB-88F6281 Device Tree Source.
  *
- * $FreeBSD: head/sys/boot/fdt/dts/db88f6281.dts 227730 2011-11-19 16:30:06Z raj $
+ * $FreeBSD: head/sys/boot/fdt/dts/db88f6281.dts 235779 2012-05-22 09:27:57Z gber $
  */
 
 /dts-v1/;
@@ -72,48 +72,33 @@
 		reg = <0x0 0x20000000>;		// 512M at 0x0
 	};
 
-	localbus at f1000000 {
+	localbus at 0 {
 		#address-cells = <2>;
 		#size-cells = <1>;
 		compatible = "mrvl,lbc";
+		bank-count = <3>;
 
 		/* This reflects CPU decode windows setup. */
-		ranges = <0x0 0x0f 0xf9300000 0x00100000
-			  0x1 0x1e 0xfa000000 0x00100000
-			  0x2 0x1d 0xfa100000 0x02000000
-			  0x3 0x1b 0xfc100000 0x00000400>;
+		ranges = <0x0 0x2f 0xf9300000 0x00100000>;
 
-		nor at 0,0 {
+		nand at 0,0 {
 			#address-cells = <1>;
 			#size-cells = <1>;
-			compatible = "cfi-flash";
+			compatible = "mrvl,nfc";
 			reg = <0x0 0x0 0x00100000>;
 			bank-width = <2>;
 			device-width = <1>;
-		};
 
-		led at 1,0 {
-			#address-cells = <1>;
-			#size-cells = <1>;
-			compatible = "led";
-			reg = <0x1 0x0 0x00100000>;
-		};
+			slice at 0 {
+				reg = <0x0 0x200000>;
+				label = "u-boot";
+				read-only;
+			};
 
-		nor at 2,0 {
-			#address-cells = <1>;
-			#size-cells = <1>;
-			compatible = "cfi-flash";
-			reg = <0x2 0x0 0x02000000>;
-			bank-width = <2>;
-			device-width = <1>;
-		};
-
-		nand at 3,0 {
-			#address-cells = <1>;
-			#size-cells = <1>;
-			reg = <0x3 0x0 0x00100000>;
-			bank-width = <2>;
-			device-width = <1>;
+			slice at 200000 {
+				reg = <0x200000 0x7e00000>;
+				label = "root";
+			};
 		};
 	};
 
@@ -305,4 +290,9 @@
 				  0x0 0x00100000>;
 		};
 	};
+
+      	chosen {
+		stdin = "serial0";
+		stdout = "serial0";
+	};
 };
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/fdt/dts/p2041rdb.dts
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/boot/fdt/dts/p2041rdb.dts	Wed Jul 25 16:45:04 2012 +0300
@@ -0,0 +1,490 @@
+/*
+ * P2041RDB Device Tree Source
+ *
+ * Copyright 2011 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/* $FreeBSD: head/sys/boot/fdt/dts/p2041rdb.dts 236024 2012-05-25 20:43:38Z raj $ */
+
+/include/ "p2041si.dtsi"
+
+/ {
+	model = "fsl,P2041RDB";
+	compatible = "fsl,P2041RDB";
+	#address-cells = <2>;
+	#size-cells = <2>;
+	interrupt-parent = <&mpic>;
+
+	aliases {
+		phy_rgmii_0 = &phy_rgmii_0;
+		phy_rgmii_1 = &phy_rgmii_1;
+		phy_sgmii_2 = &phy_sgmii_2;
+		phy_sgmii_3 = &phy_sgmii_3;
+		phy_sgmii_4 = &phy_sgmii_4;
+		phy_sgmii_1c = &phy_sgmii_1c;
+		phy_sgmii_1d = &phy_sgmii_1d;
+		phy_sgmii_1e = &phy_sgmii_1e;
+		phy_sgmii_1f = &phy_sgmii_1f;
+		phy_xgmii_2 = &phy_xgmii_2;
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x00000000 0x00000000 0x80000000>;
+	};
+
+	dcsr: dcsr at f00000000 {
+		ranges = <0x00000000 0xf 0x00000000 0x01008000>;
+	};
+
+	bman-portals at ff4000000 {
+		bman-portal at 0 {
+			cpu-handle = <&cpu0>;
+		};
+		bman-portal at 4000 {
+			cpu-handle = <&cpu1>;
+		};
+		bman-portal at 8000 {
+			cpu-handle = <&cpu2>;
+		};
+		bman-portal at c000 {
+			cpu-handle = <&cpu3>;
+		};
+		bman-portal at 10000 {
+		};
+		bman-portal at 14000 {
+		};
+		bman-portal at 18000 {
+		};
+		bman-portal at 1c000 {
+		};
+		bman-portal at 20000 {
+		};
+		bman-portal at 24000 {
+		};
+
+		buffer-pool at 0 {
+			compatible = "fsl,p2041-bpool", "fsl,bpool";
+			fsl,bpid = <0>;
+			fsl,bpool-cfg = <0 0x100 0 1 0 0x100>;
+		};
+	};
+
+	qman-portals at ff4200000 {
+		qportal0: qman-portal at 0 {
+			cpu-handle = <&cpu0>;
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal1: qman-portal at 4000 {
+			cpu-handle = <&cpu1>;
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal2: qman-portal at 8000 {
+			cpu-handle = <&cpu2>;
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal3: qman-portal at c000 {
+			cpu-handle = <&cpu3>;
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal4: qman-portal at 10000 {
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal5: qman-portal at 14000 {
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal6: qman-portal at 18000 {
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal7: qman-portal at 1c000 {
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal8: qman-portal at 20000 {
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal9: qman-portal at 24000 {
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+	};
+
+	soc: soc at ffe000000 {
+		spi at 110000 {
+			flash at 0 {
+				#address-cells = <1>;
+				#size-cells = <1>;
+				compatible = "spansion,s25sl12801";
+				reg = <0>;
+				spi-max-frequency = <40000000>; /* input clock */
+				partition at u-boot {
+					label = "u-boot";
+					reg = <0x00000000 0x00100000>;
+					read-only;
+				};
+				partition at kernel {
+					label = "kernel";
+					reg = <0x00100000 0x00500000>;
+					read-only;
+				};
+				partition at dtb {
+					label = "dtb";
+					reg = <0x00600000 0x00100000>;
+					read-only;
+				};
+				partition at fs {
+					label = "file system";
+					reg = <0x00700000 0x00900000>;
+				};
+			};
+		};
+
+		i2c at 118000 {
+			lm75b at 48 {
+				compatible = "nxp,lm75a";
+				reg = <0x48>;
+			};
+			eeprom at 50 {
+				compatible = "at24,24c256";
+				reg = <0x50>;
+			};
+			rtc at 68 {
+				compatible = "pericom,pt7c4338";
+				reg = <0x68>;
+			};
+		};
+
+		i2c at 118100 {
+			eeprom at 50 {
+				compatible = "at24,24c256";
+				reg = <0x50>;
+			};
+		};
+
+		usb1: usb at 211000 {
+			dr_mode = "host";
+		};
+
+		pme: pme at 316000 {
+			/* Commented out, use default allocation */
+			/* fsl,pme-pdsr = <0x0 0x23000000 0x0 0x01000000>; */
+			/* fsl,pme-sre = <0x0 0x24000000 0x0 0x00a00000>; */
+		};
+
+		qman: qman at 318000 {
+			/* Commented out, use default allocation */
+			/* fsl,qman-fqd = <0x0 0x20000000 0x0 0x01000000>; */
+			/* fsl,qman-pfdr = <0x0 0x21000000 0x0 0x01000000>; */
+		};
+
+		bman: bman at 31a000 {
+			/* Same as fsl,qman-*, use default allocation */
+			/* fsl,bman-fbpr = <0x0 0x22000000 0x0 0x01000000>; */
+		};
+
+		fman0: fman at 400000 {
+			enet0: ethernet at e0000 {
+				tbi-handle = <&tbi0>;
+				phy-handle = <&phy_sgmii_2>;
+				phy-connection-type = "sgmii";
+			};
+
+			mdio0: mdio at e1120 {
+				tbi0: tbi-phy at 8 {
+					reg = <0x8>;
+					device_type = "tbi-phy";
+				};
+
+				phy_rgmii_0: ethernet-phy at 0 {
+					reg = <0x0>;
+				};
+				phy_rgmii_1: ethernet-phy at 1 {
+					reg = <0x1>;
+				};
+				phy_sgmii_2: ethernet-phy at 2 {
+					reg = <0x2>;
+				};
+				phy_sgmii_3: ethernet-phy at 3 {
+					reg = <0x3>;
+				};
+				phy_sgmii_4: ethernet-phy at 4 {
+					reg = <0x4>;
+				};
+				phy_sgmii_1c: ethernet-phy at 1c {
+					reg = <0x1c>;
+				};
+				phy_sgmii_1d: ethernet-phy at 1d {
+					reg = <0x1d>;
+				};
+				phy_sgmii_1e: ethernet-phy at 1e {
+					reg = <0x1e>;
+				};
+				phy_sgmii_1f: ethernet-phy at 1f {
+					reg = <0x1f>;
+				};
+			};
+
+			enet1: ethernet at e2000 {
+				tbi-handle = <&tbi1>;
+				phy-handle = <&phy_sgmii_3>;
+				phy-connection-type = "sgmii";
+			};
+
+			mdio at e3120 {
+				tbi1: tbi-phy at 8 {
+					reg = <8>;
+					device_type = "tbi-phy";
+				};
+			};
+
+			enet2: ethernet at e4000 {
+				tbi-handle = <&tbi2>;
+				phy-handle = <&phy_sgmii_4>;
+				phy-connection-type = "sgmii";
+			};
+
+			mdio at e5120 {
+				tbi2: tbi-phy at 8 {
+					reg = <8>;
+					device_type = "tbi-phy";
+				};
+			};
+
+			enet3: ethernet at e6000 {
+				tbi-handle = <&tbi3>;
+				phy-handle = <&phy_rgmii_1>;
+				phy-connection-type = "rgmii";
+			};
+
+			mdio at e7120 {
+				tbi3: tbi-phy at 8 {
+					reg = <8>;
+					device_type = "tbi-phy";
+				};
+			};
+
+			enet4: ethernet at e8000 {
+				tbi-handle = <&tbi4>;
+				phy-handle = <&phy_rgmii_0>;
+				phy-connection-type = "rgmii";
+			};
+
+			mdio at e9120 {
+				tbi4: tbi-phy at 8 {
+					reg = <8>;
+					device_type = "tbi-phy";
+				};
+			};
+
+			enet5: ethernet at f0000 {
+				/*
+				 * phy-handle will be updated by U-Boot to
+				 * reflect the actual slot the XAUI card is in.
+				 */
+				phy-handle = <&phy_xgmii_2>;
+				phy-connection-type = "xgmii";
+			};
+
+			mdio at f1000 {
+				/* XAUI card in slot 2 */
+				phy_xgmii_2: ethernet-phy at 0 {
+					reg = <0x0>;
+				};
+			};
+		};
+	};
+
+	rapidio at ffe0c0000 {
+		reg = <0xf 0xfe0c0000 0 0x11000>;
+
+		port1 {
+			ranges = <0 0 0xc 0x20000000 0 0x10000000>;
+		};
+		port2 {
+			ranges = <0 0 0xc 0x30000000 0 0x10000000>;
+		};
+	};
+
+	localbus at ffe124000 {
+		reg = <0xf 0xfe124000 0 0x1000>;
+		ranges = <0 0 0xf 0xb8000000 0x04000000>;
+
+		flash at 0,0 {
+			compatible = "cfi-flash";
+			/*
+                         * Map 64Mb of 128MB NOR flash memory. Since highest
+                         * line of address of NOR flash memory are set by
+                         * FPGA, memory are divided into two pages equal to
+                         * 64MB. One of the pages can be accessed at once.
+                         */
+			reg = <0 0 0x04000000>;
+			bank-width = <2>;
+			device-width = <2>;
+		};
+	};
+
+	pci0: pcie at ffe200000 {
+		reg = <0xf 0xfe200000 0 0x1000>;
+		ranges = <0x02000000 0 0x80000000 0x0 0x80000000 0x0 0x10000000
+			  0x01000000 0 0x00000000 0x0 0xff000000 0x0 0x00010000>;
+		pcie at 0 {
+			ranges = <0x02000000 0 0x80000000
+				  0x02000000 0 0x80000000
+				  0 0x10000000
+
+				  0x01000000 0 0x00000000
+				  0x01000000 0 0xff000000
+				  0 0x00010000>;
+		};
+	};
+
+	pci1: pcie at ffe201000 {
+		reg = <0xf 0xfe201000 0 0x1000>;
+		ranges = <0x02000000 0x0 0x90000000 0x0 0x90000000 0x0 0x10000000
+			  0x01000000 0x0 0x00000000 0x0 0xff010000 0x0 0x00010000>;
+		pcie at 0 {
+			ranges = <0x02000000 0 0x90000000
+				  0x02000000 0 0x90000000
+				  0 0x10000000
+
+				  0x01000000 0 0x00000000
+				  0x01000000 0 0xff010000
+				  0 0x00010000>;
+		};
+	};
+
+	pci2: pcie at ffe202000 {
+		reg = <0xf 0xfe202000 0 0x1000>;
+		ranges = <0x02000000 0 0xa0000000 0x0 0xa0000000 0 0x10000000
+			  0x01000000 0 0x00000000 0x0 0xff020000 0 0x00010000>;
+		pcie at 0 {
+			ranges = <0x02000000 0 0xa0000000
+				  0x02000000 0 0xa0000000
+				  0 0x10000000
+
+				  0x01000000 0 0x00000000
+				  0x01000000 0 0xff020000
+				  0 0x00010000>;
+		};
+	};
+
+	fsl,dpaa {
+		compatible = "fsl,p2041-dpaa", "fsl,dpaa";
+
+		ethernet at 0 {
+			compatible = "fsl,p2041-dpa-ethernet", "fsl,dpa-ethernet";
+			fsl,qman-channel = <&qpool1>;
+			fsl,fman-mac = <&enet0>;
+			status = "okay";
+		};
+		ethernet at 1 {
+			compatible = "fsl,p2041-dpa-ethernet", "fsl,dpa-ethernet";
+			fsl,qman-channel = <&qpool1>;
+			fsl,fman-mac = <&enet1>;
+			status = "okay";
+		};
+		ethernet at 2 {
+			compatible = "fsl,p2041-dpa-ethernet", "fsl,dpa-ethernet";
+			fsl,qman-channel = <&qpool1>;
+			fsl,fman-mac = <&enet2>;
+			status = "okay";
+		};
+		ethernet at 3 {
+			compatible = "fsl,p2041-dpa-ethernet", "fsl,dpa-ethernet";
+			fsl,qman-channel = <&qpool1>;
+			fsl,fman-mac = <&enet3>;
+			status = "okay";
+		};
+		ethernet at 4 {
+			compatible = "fsl,p2041-dpa-ethernet", "fsl,dpa-ethernet";
+			fsl,qman-channel = <&qpool1>;
+			fsl,fman-mac = <&enet4>;
+			status = "okay";
+		};
+		ethernet at 5 {
+			compatible = "fsl,p2041-dpa-ethernet", "fsl,dpa-ethernet";
+			fsl,qman-channel = <&qpool1>;
+			fsl,fman-mac = <&enet5>;
+			status = "okay";
+		};
+	};
+
+	chosen {
+		stdin = "serial0";
+		stdout = "serial0";
+	};
+};
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/fdt/dts/p2041si.dtsi
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/boot/fdt/dts/p2041si.dtsi	Wed Jul 25 16:45:04 2012 +0300
@@ -0,0 +1,1296 @@
+/*
+ * P2041 Silicon Device Tree Source
+ *
+ * Copyright 2011 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/* $FreeBSD: head/sys/boot/fdt/dts/p2041si.dtsi 236024 2012-05-25 20:43:38Z raj $ */
+
+/dts-v1/;
+
+/ {
+	compatible = "fsl,P2041";
+	#address-cells = <2>;
+	#size-cells = <2>;
+	interrupt-parent = <&mpic>;
+
+	aliases {
+		ccsr = &soc;
+		dcsr = &dcsr;
+
+		ethernet0 = &enet0;
+		ethernet1 = &enet1;
+		ethernet2 = &enet2;
+		ethernet3 = &enet3;
+		ethernet4 = &enet4;
+		ethernet5 = &enet5;
+		serial0 = &serial0;
+		serial1 = &serial1;
+		serial2 = &serial2;
+		serial3 = &serial3;
+		pci0 = &pci0;
+		pci1 = &pci1;
+		pci2 = &pci2;
+		usb0 = &usb0;
+		usb1 = &usb1;
+		dma0 = &dma0;
+		dma1 = &dma1;
+		bman = &bman;
+		qman = &qman;
+		pme = &pme;
+		rman = &rman;
+		sdhc = &sdhc;
+		msi0 = &msi0;
+		msi1 = &msi1;
+		msi2 = &msi2;
+
+		crypto = &crypto;
+		sec_jr0 = &sec_jr0;
+		sec_jr1 = &sec_jr1;
+		sec_jr2 = &sec_jr2;
+		sec_jr3 = &sec_jr3;
+		rtic_a = &rtic_a;
+		rtic_b = &rtic_b;
+		rtic_c = &rtic_c;
+		rtic_d = &rtic_d;
+		sec_mon = &sec_mon;
+
+		fman0 = &fman0;
+		fman0_oh0 = &fman0_oh0;
+		fman0_oh1 = &fman0_oh1;
+		fman0_oh2 = &fman0_oh2;
+		fman0_oh3 = &fman0_oh3;
+		fman0_oh4 = &fman0_oh4;
+		fman0_oh5 = &fman0_oh5;
+		fman0_oh6 = &fman0_oh6;
+		fman0_rx0 = &fman0_rx0;
+		fman0_rx1 = &fman0_rx1;
+		fman0_rx2 = &fman0_rx2;
+		fman0_rx3 = &fman0_rx3;
+		fman0_rx4 = &fman0_rx4;
+		fman0_rx5 = &fman0_rx5;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu0: PowerPC,e500mc at 0 {
+			device_type = "cpu";
+			reg = <0>;
+			bus-frequency = <749999996>;
+			next-level-cache = <&L2_0>;
+			L2_0: l2-cache {
+				next-level-cache = <&cpc>;
+			};
+		};
+		cpu1: PowerPC,e500mc at 1 {
+			device_type = "cpu";
+			reg = <1>;
+			next-level-cache = <&L2_1>;
+			L2_1: l2-cache {
+				next-level-cache = <&cpc>;
+			};
+		};
+		cpu2: PowerPC,e500mc at 2 {
+			device_type = "cpu";
+			reg = <2>;
+			next-level-cache = <&L2_2>;
+			L2_2: l2-cache {
+				next-level-cache = <&cpc>;
+			};
+		};
+		cpu3: PowerPC,e500mc at 3 {
+			device_type = "cpu";
+			reg = <3>;
+			next-level-cache = <&L2_3>;
+			L2_3: l2-cache {
+				next-level-cache = <&cpc>;
+			};
+		};
+	};
+
+	dcsr: dcsr at f00000000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "fsl,dcsr", "simple-bus";
+
+		dcsr-epu at 0 {
+			compatible = "fsl,dcsr-epu";
+			interrupts = <52 2 0 0
+				      84 2 0 0
+				      85 2 0 0>;
+			interrupt-parent = <&mpic>;
+			reg = <0x0 0x1000>;
+		};
+		dcsr-npc {
+			compatible = "fsl,dcsr-npc";
+			reg = <0x1000 0x1000 0x1000000 0x8000>;
+		};
+		dcsr-nxc at 2000 {
+			compatible = "fsl,dcsr-nxc";
+			reg = <0x2000 0x1000>;
+		};
+		dcsr-corenet {
+			compatible = "fsl,dcsr-corenet";
+			reg = <0x8000 0x1000 0xB0000 0x1000>;
+		};
+		dcsr-dpaa at 9000 {
+			compatible = "fsl,p2041-dcsr-dpaa", "fsl,dcsr-dpaa";
+			reg = <0x9000 0x1000>;
+		};
+		dcsr-ocn at 11000 {
+			compatible = "fsl,p2041-dcsr-ocn", "fsl,dcsr-ocn";
+			reg = <0x11000 0x1000>;
+		};
+		dcsr-ddr at 12000 {
+			compatible = "fsl,dcsr-ddr";
+			dev-handle = <&ddr>;
+			reg = <0x12000 0x1000>;
+		};
+		dcsr-nal at 18000 {
+			compatible = "fsl,p2041-dcsr-nal", "fsl,dcsr-nal";
+			reg = <0x18000 0x1000>;
+		};
+		dcsr-rcpm at 22000 {
+			compatible = "fsl,p2041-dcsr-rcpm", "fsl,dcsr-rcpm";
+			reg = <0x22000 0x1000>;
+		};
+		dcsr-cpu-sb-proxy at 40000 {
+			compatible = "fsl,dcsr-e500mc-sb-proxy", "fsl,dcsr-cpu-sb-proxy";
+			cpu-handle = <&cpu0>;
+			reg = <0x40000 0x1000>;
+		};
+		dcsr-cpu-sb-proxy at 41000 {
+			compatible = "fsl,dcsr-e500mc-sb-proxy", "fsl,dcsr-cpu-sb-proxy";
+			cpu-handle = <&cpu1>;
+			reg = <0x41000 0x1000>;
+		};
+		dcsr-cpu-sb-proxy at 42000 {
+			compatible = "fsl,dcsr-e500mc-sb-proxy", "fsl,dcsr-cpu-sb-proxy";
+			cpu-handle = <&cpu2>;
+			reg = <0x42000 0x1000>;
+		};
+		dcsr-cpu-sb-proxy at 43000 {
+			compatible = "fsl,dcsr-e500mc-sb-proxy", "fsl,dcsr-cpu-sb-proxy";
+			cpu-handle = <&cpu3>;
+			reg = <0x43000 0x1000>;
+		};
+	};
+
+	bman-portals at ff4000000 {
+		#address-cells = <0x1>;
+		#size-cells = <0x1>;
+		compatible = "bman-portals";
+		ranges = <0x0 0xf 0xfde00000 0x200000>;
+		bman-portal at 0 {
+			cell-index = <0x0>;
+			compatible = "fsl,p2041-bman-portal", "fsl,bman-portal";
+			reg = <0x0 0x4000 0x100000 0x1000>;
+			interrupts = <105 2 0 0>;
+		};
+		bman-portal at 4000 {
+			cell-index = <0x1>;
+			compatible = "fsl,p2041-bman-portal", "fsl,bman-portal";
+			reg = <0x4000 0x4000 0x101000 0x1000>;
+			interrupts = <107 2 0 0>;
+		};
+		bman-portal at 8000 {
+			cell-index = <2>;
+			compatible = "fsl,p2041-bman-portal", "fsl,bman-portal";
+			reg = <0x8000 0x4000 0x102000 0x1000>;
+			interrupts = <109 2 0 0>;
+		};
+		bman-portal at c000 {
+			cell-index = <0x3>;
+			compatible = "fsl,p2041-bman-portal", "fsl,bman-portal";
+			reg = <0xc000 0x4000 0x103000 0x1000>;
+			interrupts = <111 2 0 0>;
+		};
+		bman-portal at 10000 {
+			cell-index = <0x4>;
+			compatible = "fsl,p2041-bman-portal", "fsl,bman-portal";
+			reg = <0x10000 0x4000 0x104000 0x1000>;
+			interrupts = <113 2 0 0>;
+		};
+		bman-portal at 14000 {
+			cell-index = <0x5>;
+			compatible = "fsl,p2041-bman-portal", "fsl,bman-portal";
+			reg = <0x14000 0x4000 0x105000 0x1000>;
+			interrupts = <115 2 0 0>;
+		};
+		bman-portal at 18000 {
+			cell-index = <0x6>;
+			compatible = "fsl,p2041-bman-portal", "fsl,bman-portal";
+			reg = <0x18000 0x4000 0x106000 0x1000>;
+			interrupts = <117 2 0 0>;
+		};
+		bman-portal at 1c000 {
+			cell-index = <0x7>;
+			compatible = "fsl,p2041-bman-portal", "fsl,bman-portal";
+			reg = <0x1c000 0x4000 0x107000 0x1000>;
+			interrupts = <119 2 0 0>;
+		};
+		bman-portal at 20000 {
+			cell-index = <0x8>;
+			compatible = "fsl,p2041-bman-portal", "fsl,bman-portal";
+			reg = <0x20000 0x4000 0x108000 0x1000>;
+			interrupts = <121 2 0 0>;
+		};
+		bman-portal at 24000 {
+			cell-index = <0x9>;
+			compatible = "fsl,p2041-bman-portal", "fsl,bman-portal";
+			reg = <0x24000 0x4000 0x109000 0x1000>;
+			interrupts = <123 2 0 0>;
+		};
+
+		buffer-pool at 0 {
+			compatible = "fsl,p2041-bpool", "fsl,bpool";
+			fsl,bpid = <0>;
+			fsl,bpool-cfg = <0 0x100 0 1 0 0x100>;
+		};
+	};
+
+	qman-portals at ff4200000 {
+		#address-cells = <0x1>;
+		#size-cells = <0x1>;
+		compatible = "qman-portals";
+		ranges = <0x0 0xf 0xfdc00000 0x200000>;
+		qportal0: qman-portal at 0 {
+			cell-index = <0x0>;
+			compatible = "fsl,p2041-qman-portal", "fsl,qman-portal";
+			reg = <0x0 0x4000 0x100000 0x1000>;
+			interrupts = <104 0x2 0 0>;
+			fsl,qman-channel-id = <0x0>;
+		};
+
+		qportal1: qman-portal at 4000 {
+			cell-index = <0x1>;
+			compatible = "fsl,p2041-qman-portal", "fsl,qman-portal";
+			reg = <0x4000 0x4000 0x101000 0x1000>;
+			interrupts = <106 0x2 0 0>;
+			fsl,qman-channel-id = <0x1>;
+		};
+
+		qportal2: qman-portal at 8000 {
+			cell-index = <0x2>;
+			compatible = "fsl,p2041-qman-portal", "fsl,qman-portal";
+			reg = <0x8000 0x4000 0x102000 0x1000>;
+			interrupts = <108 0x2 0 0>;
+			fsl,qman-channel-id = <0x2>;
+		};
+
+		qportal3: qman-portal at c000 {
+			cell-index = <0x3>;
+			compatible = "fsl,p2041-qman-portal", "fsl,qman-portal";
+			reg = <0xc000 0x4000 0x103000 0x1000>;
+			interrupts = <110 0x2 0 0>;
+			fsl,qman-channel-id = <0x3>;
+		};
+
+		qportal4: qman-portal at 10000 {
+			cell-index = <0x4>;
+			compatible = "fsl,p2041-qman-portal", "fsl,qman-portal";
+			reg = <0x10000 0x4000 0x104000 0x1000>;
+			interrupts = <112 0x2 0 0>;
+			fsl,qman-channel-id = <0x4>;
+		};
+
+		qportal5: qman-portal at 14000 {
+			cell-index = <0x5>;
+			compatible = "fsl,p2041-qman-portal", "fsl,qman-portal";
+			reg = <0x14000 0x4000 0x105000 0x1000>;
+			interrupts = <114 0x2 0 0>;
+			fsl,qman-channel-id = <0x5>;
+		};
+
+		qportal6: qman-portal at 18000 {
+			cell-index = <0x6>;
+			compatible = "fsl,p2041-qman-portal", "fsl,qman-portal";
+			reg = <0x18000 0x4000 0x106000 0x1000>;
+			interrupts = <116 0x2 0 0>;
+			fsl,qman-channel-id = <0x6>;
+		};
+
+		qportal7: qman-portal at 1c000 {
+			cell-index = <0x7>;
+			compatible = "fsl,p2041-qman-portal", "fsl,qman-portal";
+			reg = <0x1c000 0x4000 0x107000 0x1000>;
+			interrupts = <118 0x2 0 0>;
+			fsl,qman-channel-id = <0x7>;
+		};
+
+		qportal8: qman-portal at 20000 {
+			cell-index = <0x8>;
+			compatible = "fsl,p2041-qman-portal", "fsl,qman-portal";
+			reg = <0x20000 0x4000 0x108000 0x1000>;
+			interrupts = <120 0x2 0 0>;
+			fsl,qman-channel-id = <0x8>;
+		};
+
+		qportal9: qman-portal at 24000 {
+			cell-index = <0x9>;
+			compatible = "fsl,p2041-qman-portal", "fsl,qman-portal";
+			reg = <0x24000 0x4000 0x109000 0x1000>;
+			interrupts = <122 0x2 0 0>;
+			fsl,qman-channel-id = <0x9>;
+		};
+
+		qpool1: qman-pool at 1 {
+			cell-index = <1>;
+			compatible = "fsl,p2041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x21>;
+		};
+
+		qpool2: qman-pool at 2 {
+			cell-index = <2>;
+			compatible = "fsl,p2041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x22>;
+		};
+
+		qpool3: qman-pool at 3 {
+			cell-index = <3>;
+			compatible = "fsl,p2041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x23>;
+		};
+
+		qpool4: qman-pool at 4 {
+			cell-index = <4>;
+			compatible = "fsl,p2041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x24>;
+		};
+
+		qpool5: qman-pool at 5 {
+			cell-index = <5>;
+			compatible = "fsl,p2041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x25>;
+		};
+
+		qpool6: qman-pool at 6 {
+			cell-index = <6>;
+			compatible = "fsl,p2041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x26>;
+		};
+
+		qpool7: qman-pool at 7 {
+			cell-index = <7>;
+			compatible = "fsl,p2041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x27>;
+		};
+
+		qpool8: qman-pool at 8 {
+			cell-index = <8>;
+			compatible = "fsl,p2041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x28>;
+		};
+
+		qpool9: qman-pool at 9 {
+			cell-index = <9>;
+			compatible = "fsl,p2041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x29>;
+		};
+
+		qpool10: qman-pool at 10 {
+			cell-index = <10>;
+			compatible = "fsl,p2041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x2a>;
+		};
+
+		qpool11: qman-pool at 11 {
+			cell-index = <11>;
+			compatible = "fsl,p2041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x2b>;
+		};
+
+		qpool12: qman-pool at 12 {
+			cell-index = <12>;
+			compatible = "fsl,p2041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x2c>;
+		};
+
+		qpool13: qman-pool at 13 {
+			cell-index = <13>;
+			compatible = "fsl,p2041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x2d>;
+		};
+
+		qpool14: qman-pool at 14 {
+			cell-index = <14>;
+			compatible = "fsl,p2041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x2e>;
+		};
+
+		qpool15: qman-pool at 15 {
+			cell-index = <15>;
+			compatible = "fsl,p2041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x2f>;
+		};
+	};
+
+	soc: soc at ffe000000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		device_type = "soc";
+		compatible = "simple-bus";
+		
+		bus-frequency = <0>;	// Filled out by kernel.
+
+		ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
+		reg = <0xf 0xfe000000 0 0x00001000>;
+
+		soc-sram-error {
+			compatible = "fsl,soc-sram-error";
+			interrupts = <16 2 1 29>;
+		};
+
+		corenet-law at 0 {
+			compatible = "fsl,corenet-law";
+			reg = <0x0 0x1000>;
+			fsl,num-laws = <32>;
+		};
+
+		ddr: memory-controller at 8000 {
+			compatible = "fsl,qoriq-memory-controller-v4.5", "fsl,qoriq-memory-controller";
+			reg = <0x8000 0x1000>;
+			interrupts = <16 2 1 23>;
+		};
+
+		cpc: l3-cache-controller at 10000 {
+			compatible = "fsl,p2041-l3-cache-controller", "fsl,p4080-l3-cache-controller", "cache";
+			reg = <0x10000 0x1000>;
+			interrupts = <16 2 1 27>;
+		};
+
+		corenet-cf at 18000 {
+			compatible = "fsl,corenet-cf";
+			reg = <0x18000 0x1000>;
+			interrupts = <16 2 1 31>;
+			fsl,ccf-num-csdids = <32>;
+			fsl,ccf-num-snoopids = <32>;
+		};
+
+		iommu at 20000 {
+			compatible = "fsl,pamu-v1.0", "fsl,pamu";
+			reg = <0x20000 0x4000>;
+			interrupts = <
+				24 2 0 0
+				16 2 1 30>;
+		};
+
+		mpic: pic at 40000 {
+			clock-frequency = <0>;
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <4>;
+			reg = <0x40000 0x40000>;
+			compatible = "fsl,mpic", "chrp,open-pic";
+			device_type = "open-pic";
+		};
+
+		msi0: msi at 41600 {
+			compatible = "fsl,mpic-msi";
+			reg = <0x41600 0x200>;
+			msi-available-ranges = <0 0x100>;
+			interrupts = <
+				0xe0 0 0 0
+				0xe1 0 0 0
+				0xe2 0 0 0
+				0xe3 0 0 0
+				0xe4 0 0 0
+				0xe5 0 0 0
+				0xe6 0 0 0
+				0xe7 0 0 0>;
+		};
+
+		msi1: msi at 41800 {
+			compatible = "fsl,mpic-msi";
+			reg = <0x41800 0x200>;
+			msi-available-ranges = <0 0x100>;
+			interrupts = <
+				0xe8 0 0 0
+				0xe9 0 0 0
+				0xea 0 0 0
+				0xeb 0 0 0
+				0xec 0 0 0
+				0xed 0 0 0
+				0xee 0 0 0
+				0xef 0 0 0>;
+		};
+
+		msi2: msi at 41a00 {
+			compatible = "fsl,mpic-msi";
+			reg = <0x41a00 0x200>;
+			msi-available-ranges = <0 0x100>;
+			interrupts = <
+				0xf0 0 0 0
+				0xf1 0 0 0
+				0xf2 0 0 0
+				0xf3 0 0 0
+				0xf4 0 0 0
+				0xf5 0 0 0
+				0xf6 0 0 0
+				0xf7 0 0 0>;
+		};
+
+		guts: global-utilities at e0000 {
+			compatible = "fsl,qoriq-device-config-1.0";
+			reg = <0xe0000 0xe00>;
+			fsl,has-rstcr;
+			#sleep-cells = <1>;
+			fsl,liodn-bits = <12>;
+		};
+
+		pins: global-utilities at e0e00 {
+			compatible = "fsl,qoriq-pin-control-1.0";
+			reg = <0xe0e00 0x200>;
+			#sleep-cells = <2>;
+		};
+
+		clockgen: global-utilities at e1000 {
+			compatible = "fsl,p2041-clockgen", "fsl,qoriq-clockgen-1.0";
+			reg = <0xe1000 0x1000>;
+			clock-frequency = <0>;
+		};
+
+		rcpm: global-utilities at e2000 {
+			compatible = "fsl,qoriq-rcpm-1.0";
+			reg = <0xe2000 0x1000>;
+			#sleep-cells = <1>;
+		};
+
+		sfp: sfp at e8000 {
+			compatible = "fsl,p2041-sfp", "fsl,qoriq-sfp-1.0";
+			reg	   = <0xe8000 0x1000>;
+		};
+
+		serdes: serdes at ea000 {
+			compatible = "fsl,p2041-serdes";
+			reg	   = <0xea000 0x1000>;
+		};
+
+		dma0: dma at 100300 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "fsl,p2041-dma", "fsl,eloplus-dma";
+			reg = <0x100300 0x4>;
+			ranges = <0x0 0x100100 0x200>;
+			cell-index = <0>;
+			dma-channel at 0 {
+				compatible = "fsl,p2041-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x0 0x80>;
+				cell-index = <0>;
+				interrupts = <28 2 0 0>;
+			};
+			dma-channel at 80 {
+				compatible = "fsl,p2041-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x80 0x80>;
+				cell-index = <1>;
+				interrupts = <29 2 0 0>;
+			};
+			dma-channel at 100 {
+				compatible = "fsl,p2041-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x100 0x80>;
+				cell-index = <2>;
+				interrupts = <30 2 0 0>;
+			};
+			dma-channel at 180 {
+				compatible = "fsl,p2041-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x180 0x80>;
+				cell-index = <3>;
+				interrupts = <31 2 0 0>;
+			};
+		};
+
+		dma1: dma at 101300 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "fsl,p2041-dma", "fsl,eloplus-dma";
+			reg = <0x101300 0x4>;
+			ranges = <0x0 0x101100 0x200>;
+			cell-index = <1>;
+			dma-channel at 0 {
+				compatible = "fsl,p2041-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x0 0x80>;
+				cell-index = <0>;
+				interrupts = <32 2 0 0>;
+			};
+			dma-channel at 80 {
+				compatible = "fsl,p2041-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x80 0x80>;
+				cell-index = <1>;
+				interrupts = <33 2 0 0>;
+			};
+			dma-channel at 100 {
+				compatible = "fsl,p2041-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x100 0x80>;
+				cell-index = <2>;
+				interrupts = <34 2 0 0>;
+			};
+			dma-channel at 180 {
+				compatible = "fsl,p2041-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x180 0x80>;
+				cell-index = <3>;
+				interrupts = <35 2 0 0>;
+			};
+		};
+
+		spi at 110000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,p2041-espi", "fsl,mpc8536-espi";
+			reg = <0x110000 0x1000>;
+			interrupts = <53 0x2 0 0>;
+			fsl,espi-num-chipselects = <4>;
+		};
+
+		sdhc: sdhc at 114000 {
+			compatible = "fsl,p2041-esdhc", "fsl,esdhc";
+			reg = <0x114000 0x1000>;
+			interrupts = <48 2 0 0>;
+			sdhci,auto-cmd12;
+			clock-frequency = <0>;
+		};
+
+		i2c at 118000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			cell-index = <0>;
+			compatible = "fsl-i2c";
+			reg = <0x118000 0x100>;
+			interrupts = <38 2 0 0>;
+			dfsrr;
+		};
+
+		i2c at 118100 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			cell-index = <1>;
+			compatible = "fsl-i2c";
+			reg = <0x118100 0x100>;
+			interrupts = <38 2 0 0>;
+			dfsrr;
+		};
+
+		i2c at 119000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			cell-index = <2>;
+			compatible = "fsl-i2c";
+			reg = <0x119000 0x100>;
+			interrupts = <39 2 0 0>;
+			dfsrr;
+		};
+
+		i2c at 119100 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			cell-index = <3>;
+			compatible = "fsl-i2c";
+			reg = <0x119100 0x100>;
+			interrupts = <39 2 0 0>;
+			dfsrr;
+		};
+
+		serial0: serial at 11c500 {
+			cell-index = <0>;
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <0x11c500 0x100>;
+			clock-frequency = <0>;
+			interrupts = <36 2 0 0>;
+		};
+
+		serial1: serial at 11c600 {
+			cell-index = <1>;
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <0x11c600 0x100>;
+			clock-frequency = <0>;
+			interrupts = <36 2 0 0>;
+		};
+
+		serial2: serial at 11d500 {
+			cell-index = <2>;
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <0x11d500 0x100>;
+			clock-frequency = <0>;
+			interrupts = <37 2 0 0>;
+		};
+
+		serial3: serial at 11d600 {
+			cell-index = <3>;
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <0x11d600 0x100>;
+			clock-frequency = <0>;
+			interrupts = <37 2 0 0>;
+		};
+
+		gpio0: gpio at 130000 {
+			compatible = "fsl,p2041-gpio", "fsl,qoriq-gpio";
+			reg = <0x130000 0x1000>;
+			interrupts = <55 2 0 0>;
+			#gpio-cells = <2>;
+			gpio-controller;
+		};
+
+		rman: rman at 1e0000 {
+			compatible = "fsl,rman";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x0 0x1e0000 0x20000>;
+			reg = <0x1e0000 0x20000>;
+			interrupts = <16 2 1 11>; /* err_irq */
+			fsl,qman-channels-id = <0x62 0x63>;
+
+			inbound-block at 0 {
+				compatible = "fsl,rman-inbound-block";
+				reg = <0x0 0x800>;
+			};
+			global-cfg at b00 {
+				compatible = "fsl,rman-global-cfg";
+				reg = <0xb00 0x500>;
+			};
+			inbound-block at 1000 {
+				compatible = "fsl,rman-inbound-block";
+				reg = <0x1000 0x800>;
+			};
+			inbound-block at 2000 {
+				compatible = "fsl,rman-inbound-block";
+				reg = <0x2000 0x800>;
+			};
+			inbound-block at 3000 {
+				compatible = "fsl,rman-inbound-block";
+				reg = <0x3000 0x800>;
+			};
+		};
+
+		usb0: usb at 210000 {
+			compatible = "fsl,p2041-usb2-mph",
+					"fsl,mpc85xx-usb2-mph", "fsl-usb2-mph";
+			reg = <0x210000 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			interrupts = <44 0x2 0 0>;
+			phy_type = "utmi";
+			port0;
+		};
+
+		usb1: usb at 211000 {
+			compatible = "fsl,p2041-usb2-dr",
+					"fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
+			reg = <0x211000 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			interrupts = <45 0x2 0 0>;
+			phy_type = "utmi";
+		};
+
+		sata at 220000 {
+			compatible = "fsl,p2041-sata", "fsl,pq-sata-v2";
+			reg = <0x220000 0x1000>;
+			interrupts = <68 0x2 0 0>;
+		};
+
+		sata at 221000 {
+			compatible = "fsl,p2041-sata", "fsl,pq-sata-v2";
+			reg = <0x221000 0x1000>;
+			interrupts = <69 0x2 0 0>;
+		};
+
+		crypto: crypto at 300000 {
+			compatible = "fsl,sec-v4.2", "fsl,sec-v4.0";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0x300000 0x10000>;
+			ranges = <0 0x300000 0x10000>;
+			interrupts = <92 2 0 0>;
+
+			sec_jr0: jr at 1000 {
+				compatible = "fsl,sec-v4.2-job-ring",
+					     "fsl,sec-v4.0-job-ring";
+				reg = <0x1000 0x1000>;
+				interrupts = <88 2 0 0>;
+			};
+
+			sec_jr1: jr at 2000 {
+				compatible = "fsl,sec-v4.2-job-ring",
+					     "fsl,sec-v4.0-job-ring";
+				reg = <0x2000 0x1000>;
+				interrupts = <89 2 0 0>;
+			};
+
+			sec_jr2: jr at 3000 {
+				compatible = "fsl,sec-v4.2-job-ring",
+					     "fsl,sec-v4.0-job-ring";
+				reg = <0x3000 0x1000>;
+				interrupts = <90 2 0 0>;
+			};
+
+			sec_jr3: jr at 4000 {
+				compatible = "fsl,sec-v4.2-job-ring",
+					     "fsl,sec-v4.0-job-ring";
+				reg = <0x4000 0x1000>;
+				interrupts = <91 2 0 0>;
+			};
+
+			rtic at 6000 {
+				compatible = "fsl,sec-v4.2-rtic",
+					     "fsl,sec-v4.0-rtic";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				reg = <0x6000 0x100>;
+				ranges = <0x0 0x6100 0xe00>;
+
+				rtic_a: rtic-a at 0 {
+					compatible = "fsl,sec-v4.2-rtic-memory",
+						     "fsl,sec-v4.0-rtic-memory";
+					reg = <0x00 0x20 0x100 0x80>;
+				};
+
+				rtic_b: rtic-b at 20 {
+					compatible = "fsl,sec-v4.2-rtic-memory",
+						     "fsl,sec-v4.0-rtic-memory";
+					reg = <0x20 0x20 0x200 0x80>;
+				};
+
+				rtic_c: rtic-c at 40 {
+					compatible = "fsl,sec-v4.2-rtic-memory",
+						     "fsl,sec-v4.0-rtic-memory";
+					reg = <0x40 0x20 0x300 0x80>;
+				};
+
+				rtic_d: rtic-d at 60 {
+					compatible = "fsl,sec-v4.2-rtic-memory",
+						     "fsl,sec-v4.0-rtic-memory";
+					reg = <0x60 0x20 0x500 0x80>;
+				};
+			};
+		};
+
+		sec_mon: sec_mon at 314000 {
+			compatible = "fsl,sec-v4.2-mon", "fsl,sec-v4.0-mon";
+			reg = <0x314000 0x1000>;
+			interrupts = <93 2 0 0>;
+		};
+
+		pme: pme at 316000 {
+			compatible = "fsl,pme";
+			reg = <0x316000 0x10000>;
+			/* fsl,pme-pdsr = <0x0 0x23000000 0x0 0x01000000>; */
+			/* fsl,pme-sre = <0x0 0x24000000 0x0 0x00a00000>; */
+			interrupts = <16 2 1 5>;
+		};
+
+		qman: qman at 318000 {
+			compatible = "fsl,p2041-qman", "fsl,qman";
+			reg = <0x318000 0x1000>;
+			interrupts = <16 2 1 3>;
+			/* Commented out, use default allocation */
+			/* fsl,qman-fqd = <0x0 0x20000000 0x0 0x01000000>; */
+			/* fsl,qman-pfdr = <0x0 0x21000000 0x0 0x01000000>; */
+		};
+
+		bman: bman at 31a000 {
+			compatible = "fsl,p2041-bman", "fsl,bman";
+			reg = <0x31a000 0x1000>;
+			interrupts = <16 2 1 2>;
+			/* Same as fsl,qman-*, use default allocation */
+			/* fsl,bman-fbpr = <0x0 0x22000000 0x0 0x01000000>; */
+		};
+
+		fman0: fman at 400000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			cell-index = <0>;
+			compatible = "fsl,p2041-fman", "fsl,fman", "simple-bus";
+			ranges = <0 0x400000 0x100000>;
+			reg = <0x400000 0x100000>;
+			clock-frequency = <0>;
+			interrupts = <
+				96 2 0 0
+				16 2 1 1>;
+
+			cc at 0 {
+				compatible = "fsl,p2041-fman-cc", "fsl,fman-cc";
+			};
+
+			parser at c7000 {
+				compatible = "fsl,p2041-fman-parser", "fsl,fman-parser";
+				reg = <0xc7000 0x1000>;
+			};
+
+			keygen at c1000 {
+				compatible = "fsl,p2041-fman-keygen", "fsl,fman-keygen";
+				reg = <0xc1000 0x1000>;
+			};
+
+			policer at c0000 {
+				compatible = "fsl,p2041-fman-policer", "fsl,fman-policer";
+				reg = <0xc0000 0x1000>;
+			};
+
+			muram at 0 {
+				compatible = "fsl,p2041-fman-muram", "fsl,fman-muram";
+				reg = <0x0 0x28000>;
+			};
+
+			bmi at 80000 {
+				compatible = "fsl,p2041-fman-bmi", "fsl,fman-bmi";
+				reg = <0x80000 0x400>;
+			};
+
+			qmi at 80400 {
+				compatible = "fsl,p2041-fman-qmi", "fsl,fman-qmi";
+				reg = <0x80400 0x400>;
+			};
+
+			fman0_rx0: port at 88000 {
+				cell-index = <0>;
+				compatible = "fsl,p2041-fman-port-1g-rx", "fsl,fman-port-1g-rx";
+				reg = <0x88000 0x1000>;
+			};
+			fman0_rx1: port at 89000 {
+				cell-index = <1>;
+				compatible = "fsl,p2041-fman-port-1g-rx", "fsl,fman-port-1g-rx";
+				reg = <0x89000 0x1000>;
+			};
+			fman0_rx2: port at 8a000 {
+				cell-index = <2>;
+				compatible = "fsl,p2041-fman-port-1g-rx", "fsl,fman-port-1g-rx";
+				reg = <0x8a000 0x1000>;
+			};
+			fman0_rx3: port at 8b000 {
+				cell-index = <3>;
+				compatible = "fsl,p2041-fman-port-1g-rx", "fsl,fman-port-1g-rx";
+				reg = <0x8b000 0x1000>;
+			};
+			fman0_rx4: port at 8c000 {
+				cell-index = <4>;
+				compatible = "fsl,p2041-fman-port-1g-rx", "fsl,fman-port-1g-rx";
+				reg = <0x8c000 0x1000>;
+			};
+			fman0_rx5: port at 90000 {
+				cell-index = <0>;
+				compatible = "fsl,p2041-fman-port-10g-rx", "fsl,fman-port-10g-rx";
+				reg = <0x90000 0x1000>;
+			};
+
+			fman0_tx5: port at b0000 {
+				cell-index = <0>;
+				compatible = "fsl,p2041-fman-port-10g-tx", "fsl,fman-port-10g-tx";
+				reg = <0xb0000 0x1000>;
+				fsl,qman-channel-id = <0x40>;
+			};
+			fman0_tx0: port at a8000 {
+				cell-index = <0>;
+				compatible = "fsl,p2041-fman-port-1g-tx", "fsl,fman-port-1g-tx";
+				reg = <0xa8000 0x1000>;
+				fsl,qman-channel-id = <0x41>;
+			};
+			fman0_tx1: port at a9000 {
+				cell-index = <1>;
+				compatible = "fsl,p2041-fman-port-1g-tx", "fsl,fman-port-1g-tx";
+				reg = <0xa9000 0x1000>;
+				fsl,qman-channel-id = <0x42>;
+			};
+			fman0_tx2: port at aa000 {
+				cell-index = <2>;
+				compatible = "fsl,p2041-fman-port-1g-tx", "fsl,fman-port-1g-tx";
+				reg = <0xaa000 0x1000>;
+				fsl,qman-channel-id = <0x43>;
+			};
+			fman0_tx3: port at ab000 {
+				cell-index = <3>;
+				compatible = "fsl,p2041-fman-port-1g-tx", "fsl,fman-port-1g-tx";
+				reg = <0xab000 0x1000>;
+				fsl,qman-channel-id = <0x44>;
+			};
+			fman0_tx4: port at ac000 {
+				cell-index = <4>;
+				compatible = "fsl,p2041-fman-port-1g-tx", "fsl,fman-port-1g-tx";
+				reg = <0xac000 0x1000>;
+				fsl,qman-channel-id = <0x45>;
+			};
+
+			fman0_oh0: port at 81000 {
+				cell-index = <0>;
+				compatible = "fsl,p2041-fman-port-oh", "fsl,fman-port-oh";
+				reg = <0x81000 0x1000>;
+				fsl,qman-channel-id = <0x46>;
+			};
+			fman0_oh1: port at 82000 {
+				cell-index = <1>;
+				compatible = "fsl,p2041-fman-port-oh", "fsl,fman-port-oh";
+				reg = <0x82000 0x1000>;
+				fsl,qman-channel-id = <0x47>;
+			};
+			fman0_oh2: port at 83000 {
+				cell-index = <2>;
+				compatible = "fsl,p2041-fman-port-oh", "fsl,fman-port-oh";
+				reg = <0x83000 0x1000>;
+				fsl,qman-channel-id = <0x48>;
+			};
+			fman0_oh3: port at 84000 {
+				cell-index = <3>;
+				compatible = "fsl,p2041-fman-port-oh", "fsl,fman-port-oh";
+				reg = <0x84000 0x1000>;
+				fsl,qman-channel-id = <0x49>;
+			};
+			fman0_oh4: port at 85000 {
+				cell-index = <4>;
+				compatible = "fsl,p2041-fman-port-oh", "fsl,fman-port-oh";
+				reg = <0x85000 0x1000>;
+				fsl,qman-channel-id = <0x4a>;
+			};
+			fman0_oh5: port at 86000 {
+				cell-index = <5>;
+				compatible = "fsl,p2041-fman-port-oh", "fsl,fman-port-oh";
+				reg = <0x86000 0x1000>;
+				fsl,qman-channel-id = <0x4b>;
+			};
+			fman0_oh6: port at 87000 {
+				cell-index = <6>;
+				compatible = "fsl,p2041-fman-port-oh", "fsl,fman-port-oh";
+				reg = <0x87000 0x1000>;
+			};
+
+			enet0: ethernet at e0000 {
+				cell-index = <0>;
+				compatible = "fsl,p2041-fman-1g-mac", "fsl,fman-1g-mac";
+				reg = <0xe0000 0x1000>;
+				fsl,port-handles = <&fman0_rx0 &fman0_tx0>;
+			};
+
+			mdio0: mdio at e1120 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,fman-mdio";
+				reg = <0xe1120 0xee0>;
+				interrupts = <100 1 0 0>;
+			};
+
+			enet1: ethernet at e2000 {
+				cell-index = <1>;
+				compatible = "fsl,p2041-fman-1g-mac", "fsl,fman-1g-mac";
+				reg = <0xe2000 0x1000>;
+				fsl,port-handles = <&fman0_rx1 &fman0_tx1>;
+			};
+
+			mdio at e3120 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,fman-tbi";
+				reg = <0xe3120 0xee0>;
+				interrupts = <100 1 0 0>;
+			};
+
+			enet2: ethernet at e4000 {
+				cell-index = <2>;
+				compatible = "fsl,p2041-fman-1g-mac", "fsl,fman-1g-mac";
+				reg = <0xe4000 0x1000>;
+				fsl,port-handles = <&fman0_rx2 &fman0_tx2>;
+			};
+
+			mdio at e5120 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,fman-tbi";
+				reg = <0xe5120 0xee0>;
+				interrupts = <100 1 0 0>;
+			};
+
+			enet3: ethernet at e6000 {
+				cell-index = <3>;
+				compatible = "fsl,p2041-fman-1g-mac", "fsl,fman-1g-mac";
+				reg = <0xe6000 0x1000>;
+				fsl,port-handles = <&fman0_rx3 &fman0_tx3>;
+			};
+
+			mdio at e7120 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,fman-tbi";
+				reg = <0xe7120 0xee0>;
+				interrupts = <100 1 0 0>;
+			};
+
+			enet4: ethernet at e8000 {
+				cell-index = <4>;
+				compatible = "fsl,p2041-fman-1g-mac", "fsl,fman-1g-mac";
+				reg = <0xe8000 0x1000>;
+				fsl,port-handles = <&fman0_rx4 &fman0_tx4>;
+			};
+
+			mdio at e9120 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,fman-tbi";
+				reg = <0xe9120 0xee0>;
+				interrupts = <100 1 0 0>;
+			};
+
+			enet5: ethernet at f0000 {
+				cell-index = <0>;
+				compatible = "fsl,p2041-fman-10g-mac", "fsl,fman-10g-mac";
+				reg = <0xf0000 0x1000>;
+				fsl,port-handles = <&fman0_rx5 &fman0_tx5>;
+			};
+
+			mdio at f1000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,fman-xmdio";
+				reg = <0xf1000 0x1000>;
+				interrupts = <100 1 0 0>;
+			};
+		};
+	};
+
+	rapidio at ffe0c0000 {
+		compatible = "fsl,srio";
+		interrupts = <16 2 1 11>;
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		port1 {
+			#address-cells = <2>;
+			#size-cells = <2>;
+			cell-index = <1>;
+		};
+
+		port2 {
+			#address-cells = <2>;
+			#size-cells = <2>;
+			cell-index = <2>;
+		};
+	};
+
+	localbus at ffe124000 {
+		compatible = "fsl,p2041-elbc", "fsl,elbc", "simple-bus";
+		interrupts = <25 2 0 0>;
+		#address-cells = <2>;
+		#size-cells = <1>;
+	};
+
+	pci0: pcie at ffe200000 {
+		compatible = "fsl,p2041-pcie", "fsl,qoriq-pcie-v2.2";
+		device_type = "pci";
+		status = "disabled";
+		#size-cells = <2>;
+		#address-cells = <3>;
+		bus-range = <0x0 0xff>;
+		clock-frequency = <33333333>;
+		fsl,msi = <&msi0>;
+		interrupts = <16 2 1 15>;
+		pcie at 0 {
+			reg = <0 0 0 0 0>;
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			device_type = "pci";
+			interrupts = <16 2 1 15>;
+			interrupt-map-mask = <0xf800 0 0 7>;
+			interrupt-map = <
+				/* IDSEL 0x0 */
+				0000 0 0 1 &mpic 40 1 0 0
+				0000 0 0 2 &mpic 1 1 0 0
+				0000 0 0 3 &mpic 2 1 0 0
+				0000 0 0 4 &mpic 3 1 0 0
+				>;
+		};
+	};
+
+	pci1: pcie at ffe201000 {
+		compatible = "fsl,p2041-pcie", "fsl,qoriq-pcie-v2.2";
+		device_type = "pci";
+		status = "okay";
+		#size-cells = <2>;
+		#address-cells = <3>;
+		bus-range = <0 0xff>;
+		clock-frequency = <33333333>;
+		fsl,msi = <&msi1>;
+		interrupts = <16 2 1 14>;
+		pcie at 0 {
+			reg = <0 0 0 0 0>;
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			device_type = "pci";
+			interrupts = <16 2 1 14>;
+			interrupt-map-mask = <0xf800 0 0 7>;
+			interrupt-map = <
+				/* IDSEL 0x0 */
+				0000 0 0 1 &mpic 41 1 0 0
+				0000 0 0 2 &mpic 5 1 0 0
+				0000 0 0 3 &mpic 6 1 0 0
+				0000 0 0 4 &mpic 7 1 0 0
+				>;
+		};
+	};
+
+	pci2: pcie at ffe202000 {
+		compatible = "fsl,p2041-pcie", "fsl,qoriq-pcie-v2.2";
+		device_type = "pci";
+		status = "disabled";
+		#size-cells = <2>;
+		#address-cells = <3>;
+		bus-range = <0x0 0xff>;
+		clock-frequency = <33333333>;
+		fsl,msi = <&msi2>;
+		interrupts = <16 2 1 13>;
+		pcie at 0 {
+			reg = <0 0 0 0 0>;
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			device_type = "pci";
+			interrupts = <16 2 1 13>;
+			interrupt-map-mask = <0xf800 0 0 7>;
+			interrupt-map = <
+				/* IDSEL 0x0 */
+				0000 0 0 1 &mpic 42 1 0 0
+				0000 0 0 2 &mpic 9 1 0 0
+				0000 0 0 3 &mpic 10 1 0 0
+				0000 0 0 4 &mpic 11 1 0 0
+				>;
+		};
+	};
+};
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/fdt/dts/p3041ds.dts
--- a/head/sys/boot/fdt/dts/p3041ds.dts	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/fdt/dts/p3041ds.dts	Wed Jul 25 16:45:04 2012 +0300
@@ -31,9 +31,9 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/* $FreeBSD: head/sys/boot/fdt/dts/p3041ds.dts 227506 2011-11-14 18:51:39Z marcel $ */
+/* $FreeBSD: head/sys/boot/fdt/dts/p3041ds.dts 236024 2012-05-25 20:43:38Z raj $ */
 
-/dts-v1/;
+/include/ "p3041si.dtsi"
 
 / {
 	model = "fsl,P3041DS";
@@ -43,305 +43,155 @@
 	interrupt-parent = <&mpic>;
 
 	aliases {
-		ccsr = &soc;
-
-		serial0 = &serial0;
-		serial1 = &serial1;
-		serial2 = &serial2;
-		serial3 = &serial3;
-		pci0 = &pci0;
-		pci1 = &pci1;
-		pci2 = &pci2;
-		pci3 = &pci3;
-		usb0 = &usb0;
-		usb1 = &usb1;
-		dma0 = &dma0;
-		dma1 = &dma1;
-		sdhc = &sdhc;
-		msi0 = &msi0;
-		msi1 = &msi1;
-		msi2 = &msi2;
-
-		crypto = &crypto;
-		sec_jr0 = &sec_jr0;
-		sec_jr1 = &sec_jr1;
-		sec_jr2 = &sec_jr2;
-		sec_jr3 = &sec_jr3;
-		rtic_a = &rtic_a;
-		rtic_b = &rtic_b;
-		rtic_c = &rtic_c;
-		rtic_d = &rtic_d;
-		sec_mon = &sec_mon;
-	};
-
-	cpus {
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		cpu0: PowerPC,e500mc at 0 {
-			device_type = "cpu";
-			reg = <0>;
-			next-level-cache = <&L2_0>;
-			L2_0: l2-cache {
-				next-level-cache = <&cpc>;
-			};
-		};
-		cpu1: PowerPC,e500mc at 1 {
-			device_type = "cpu";
-			reg = <1>;
-			next-level-cache = <&L2_1>;
-			L2_1: l2-cache {
-				next-level-cache = <&cpc>;
-			};
-		};
-		cpu2: PowerPC,e500mc at 2 {
-			device_type = "cpu";
-			reg = <2>;
-			next-level-cache = <&L2_2>;
-			L2_2: l2-cache {
-				next-level-cache = <&cpc>;
-			};
-		};
-		cpu3: PowerPC,e500mc at 3 {
-			device_type = "cpu";
-			reg = <3>;
-			next-level-cache = <&L2_3>;
-			L2_3: l2-cache {
-				next-level-cache = <&cpc>;
-			};
-		};
+		phy_rgmii_0 = &phy_rgmii_0;
+		phy_rgmii_1 = &phy_rgmii_1;
+		phy_sgmii_1c = &phy_sgmii_1c;
+		phy_sgmii_1d = &phy_sgmii_1d;
+		phy_sgmii_1e = &phy_sgmii_1e;
+		phy_sgmii_1f = &phy_sgmii_1f;
+		phy_xgmii_1 = &phy_xgmii_1;
+		phy_xgmii_2 = &phy_xgmii_2;
+		emi1_rgmii = &hydra_mdio_rgmii;
+		emi1_sgmii = &hydra_mdio_sgmii;
+		emi2_xgmii = &hydra_mdio_xgmii;
 	};
 
 	memory {
 		device_type = "memory";
+		reg = <0x00000000 0x00000000 0x00000000 0x80000000>;
+	};
+
+	dcsr: dcsr at f00000000 {
+		ranges = <0x00000000 0xf 0x00000000 0x01008000>;
+	};
+
+	bman-portals at ff4000000 {
+		bman-portal at 0 {
+			cpu-handle = <&cpu0>;
+		};
+		bman-portal at 4000 {
+			cpu-handle = <&cpu1>;
+		};
+		bman-portal at 8000 {
+			cpu-handle = <&cpu2>;
+		};
+		bman-portal at c000 {
+			cpu-handle = <&cpu3>;
+		};
+		bman-portal at 10000 {
+		};
+		bman-portal at 14000 {
+		};
+		bman-portal at 18000 {
+		};
+		bman-portal at 1c000 {
+		};
+		bman-portal at 20000 {
+		};
+		bman-portal at 24000 {
+		};
+
+		buffer-pool at 0 {
+			compatible = "fsl,p3041-bpool", "fsl,bpool";
+			fsl,bpid = <0>;
+			fsl,bpool-cfg = <0 0x100 0 1 0 0x100>;
+		};
+	};
+
+	qman-portals at ff4200000 {
+		qportal0: qman-portal at 0 {
+			cpu-handle = <&cpu0>;
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal1: qman-portal at 4000 {
+			cpu-handle = <&cpu1>;
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal2: qman-portal at 8000 {
+			cpu-handle = <&cpu2>;
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal3: qman-portal at c000 {
+			cpu-handle = <&cpu3>;
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal4: qman-portal at 10000 {
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal5: qman-portal at 14000 {
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal6: qman-portal at 18000 {
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal7: qman-portal at 1c000 {
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal8: qman-portal at 20000 {
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal9: qman-portal at 24000 {
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
 	};
 
 	soc: soc at ffe000000 {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		device_type = "soc";
-		compatible = "simple-bus";
-		ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
-		reg = <0xf 0xfe000000 0 0x00001000>;
-
-		soc-sram-error {
-			compatible = "fsl,soc-sram-error";
-			interrupts = <16 2 1 29>;
-		};
-
-		corenet-law at 0 {
-			compatible = "fsl,corenet-law";
-			reg = <0x0 0x1000>;
-			fsl,num-laws = <32>;
-		};
-
-		memory-controller at 8000 {
-			compatible = "fsl,qoriq-memory-controller-v4.5", "fsl,qoriq-memory-controller";
-			reg = <0x8000 0x1000>;
-			interrupts = <16 2 1 23>;
-		};
-
-		cpc: l3-cache-controller at 10000 {
-			compatible = "fsl,p3041-l3-cache-controller", "fsl,p4080-l3-cache-controller", "cache";
-			reg = <0x10000 0x1000>;
-			interrupts = <16 2 1 27>;
-		};
-
-		corenet-cf at 18000 {
-			compatible = "fsl,corenet-cf";
-			reg = <0x18000 0x1000>;
-			interrupts = <16 2 1 31>;
-			fsl,ccf-num-csdids = <32>;
-			fsl,ccf-num-snoopids = <32>;
-		};
-
-		iommu at 20000 {
-			compatible = "fsl,pamu-v1.0", "fsl,pamu";
-			reg = <0x20000 0x4000>;
-			interrupts = <
-				24 2 0 0
-				16 2 1 30>;
-		};
-
-		mpic: pic at 40000 {
-			clock-frequency = <0>;
-			interrupt-controller;
-			#address-cells = <0>;
-			#interrupt-cells = <4>;
-			reg = <0x40000 0x40000>;
-			compatible = "fsl,mpic", "chrp,open-pic";
-			device_type = "open-pic";
-		};
-
-		msi0: msi at 41600 {
-			compatible = "fsl,mpic-msi";
-			reg = <0x41600 0x200>;
-			msi-available-ranges = <0 0x100>;
-			interrupts = <
-				0xe0 0 0 0
-				0xe1 0 0 0
-				0xe2 0 0 0
-				0xe3 0 0 0
-				0xe4 0 0 0
-				0xe5 0 0 0
-				0xe6 0 0 0
-				0xe7 0 0 0>;
-		};
-
-		msi1: msi at 41800 {
-			compatible = "fsl,mpic-msi";
-			reg = <0x41800 0x200>;
-			msi-available-ranges = <0 0x100>;
-			interrupts = <
-				0xe8 0 0 0
-				0xe9 0 0 0
-				0xea 0 0 0
-				0xeb 0 0 0
-				0xec 0 0 0
-				0xed 0 0 0
-				0xee 0 0 0
-				0xef 0 0 0>;
-		};
-
-		msi2: msi at 41a00 {
-			compatible = "fsl,mpic-msi";
-			reg = <0x41a00 0x200>;
-			msi-available-ranges = <0 0x100>;
-			interrupts = <
-				0xf0 0 0 0
-				0xf1 0 0 0
-				0xf2 0 0 0
-				0xf3 0 0 0
-				0xf4 0 0 0
-				0xf5 0 0 0
-				0xf6 0 0 0
-				0xf7 0 0 0>;
-		};
-
-		guts: global-utilities at e0000 {
-			compatible = "fsl,qoriq-device-config-1.0";
-			reg = <0xe0000 0xe00>;
-			fsl,has-rstcr;
-			#sleep-cells = <1>;
-			fsl,liodn-bits = <12>;
-		};
-
-		pins: global-utilities at e0e00 {
-			compatible = "fsl,qoriq-pin-control-1.0";
-			reg = <0xe0e00 0x200>;
-			#sleep-cells = <2>;
-		};
-
-		clockgen: global-utilities at e1000 {
-			compatible = "fsl,p3041-clockgen", "fsl,qoriq-clockgen-1.0";
-			reg = <0xe1000 0x1000>;
-			clock-frequency = <0>;
-		};
-
-		rcpm: global-utilities at e2000 {
-			compatible = "fsl,qoriq-rcpm-1.0";
-			reg = <0xe2000 0x1000>;
-			#sleep-cells = <1>;
-		};
-
-		sfp: sfp at e8000 {
-			compatible = "fsl,p3041-sfp", "fsl,qoriq-sfp-1.0";
-			reg	   = <0xe8000 0x1000>;
-		};
-
-		serdes: serdes at ea000 {
-			compatible = "fsl,p3041-serdes";
-			reg	   = <0xea000 0x1000>;
-		};
-
-		dma0: dma at 100300 {
-			#address-cells = <1>;
-			#size-cells = <1>;
-			compatible = "fsl,p3041-dma", "fsl,eloplus-dma";
-			reg = <0x100300 0x4>;
-			ranges = <0x0 0x100100 0x200>;
-			cell-index = <0>;
-			dma-channel at 0 {
-				compatible = "fsl,p3041-dma-channel",
-						"fsl,eloplus-dma-channel";
-				reg = <0x0 0x80>;
-				cell-index = <0>;
-				interrupts = <28 2 0 0>;
-			};
-			dma-channel at 80 {
-				compatible = "fsl,p3041-dma-channel",
-						"fsl,eloplus-dma-channel";
-				reg = <0x80 0x80>;
-				cell-index = <1>;
-				interrupts = <29 2 0 0>;
-			};
-			dma-channel at 100 {
-				compatible = "fsl,p3041-dma-channel",
-						"fsl,eloplus-dma-channel";
-				reg = <0x100 0x80>;
-				cell-index = <2>;
-				interrupts = <30 2 0 0>;
-			};
-			dma-channel at 180 {
-				compatible = "fsl,p3041-dma-channel",
-						"fsl,eloplus-dma-channel";
-				reg = <0x180 0x80>;
-				cell-index = <3>;
-				interrupts = <31 2 0 0>;
-			};
-		};
-
-		dma1: dma at 101300 {
-			#address-cells = <1>;
-			#size-cells = <1>;
-			compatible = "fsl,p3041-dma", "fsl,eloplus-dma";
-			reg = <0x101300 0x4>;
-			ranges = <0x0 0x101100 0x200>;
-			cell-index = <1>;
-			dma-channel at 0 {
-				compatible = "fsl,p3041-dma-channel",
-						"fsl,eloplus-dma-channel";
-				reg = <0x0 0x80>;
-				cell-index = <0>;
-				interrupts = <32 2 0 0>;
-			};
-			dma-channel at 80 {
-				compatible = "fsl,p3041-dma-channel",
-						"fsl,eloplus-dma-channel";
-				reg = <0x80 0x80>;
-				cell-index = <1>;
-				interrupts = <33 2 0 0>;
-			};
-			dma-channel at 100 {
-				compatible = "fsl,p3041-dma-channel",
-						"fsl,eloplus-dma-channel";
-				reg = <0x100 0x80>;
-				cell-index = <2>;
-				interrupts = <34 2 0 0>;
-			};
-			dma-channel at 180 {
-				compatible = "fsl,p3041-dma-channel",
-						"fsl,eloplus-dma-channel";
-				reg = <0x180 0x80>;
-				cell-index = <3>;
-				interrupts = <35 2 0 0>;
-			};
-		};
-
 		spi at 110000 {
-			#address-cells = <1>;
-			#size-cells = <0>;
-			compatible = "fsl,p3041-espi", "fsl,mpc8536-espi";
-			reg = <0x110000 0x1000>;
-			interrupts = <53 0x2 0 0>;
-			fsl,espi-num-chipselects = <4>;
-
 			flash at 0 {
 				#address-cells = <1>;
 				#size-cells = <1>;
 				compatible = "spansion,s25sl12801";
 				reg = <0>;
-				spi-max-frequency = <40000000>; /* input clock */
+				spi-max-frequency = <35000000>; /* input clock */
 				partition at u-boot {
 					label = "u-boot";
 					reg = <0x00000000 0x00100000>;
@@ -364,32 +214,7 @@
 			};
 		};
 
-		sdhc: sdhc at 114000 {
-			compatible = "fsl,p3041-esdhc", "fsl,esdhc";
-			reg = <0x114000 0x1000>;
-			interrupts = <48 2 0 0>;
-			sdhci,auto-cmd12;
-			clock-frequency = <0>;
-		};
-
-		i2c at 118000 {
-			#address-cells = <1>;
-			#size-cells = <0>;
-			cell-index = <0>;
-			compatible = "fsl-i2c";
-			reg = <0x118000 0x100>;
-			interrupts = <38 2 0 0>;
-			dfsrr;
-		};
-
 		i2c at 118100 {
-			#address-cells = <1>;
-			#size-cells = <0>;
-			cell-index = <1>;
-			compatible = "fsl-i2c";
-			reg = <0x118100 0x100>;
-			interrupts = <38 2 0 0>;
-			dfsrr;
 			eeprom at 51 {
 				compatible = "at24,24c256";
 				reg = <0x51>;
@@ -400,24 +225,7 @@
 			};
 		};
 
-		i2c at 119000 {
-			#address-cells = <1>;
-			#size-cells = <0>;
-			cell-index = <2>;
-			compatible = "fsl-i2c";
-			reg = <0x119000 0x100>;
-			interrupts = <39 2 0 0>;
-			dfsrr;
-		};
-
 		i2c at 119100 {
-			#address-cells = <1>;
-			#size-cells = <0>;
-			cell-index = <3>;
-			compatible = "fsl-i2c";
-			reg = <0x119100 0x100>;
-			interrupts = <39 2 0 0>;
-			dfsrr;
 			rtc at 68 {
 				compatible = "dallas,ds3232";
 				reg = <0x68>;
@@ -425,329 +233,355 @@
 			};
 		};
 
-		serial0: serial at 11c500 {
-			cell-index = <0>;
-			device_type = "serial";
-			compatible = "ns16550";
-			reg = <0x11c500 0x100>;
-			clock-frequency = <0>;
-			interrupts = <36 2 0 0>;
+		pme: pme at 316000 {
+			/* Commented out, use default allocation */
+			/* fsl,pme-pdsr = <0x0 0x23000000 0x0 0x01000000>; */
+			/* fsl,pme-sre = <0x0 0x24000000 0x0 0x00a00000>; */
 		};
 
-		serial1: serial at 11c600 {
-			cell-index = <1>;
-			device_type = "serial";
-			compatible = "ns16550";
-			reg = <0x11c600 0x100>;
-			clock-frequency = <0>;
-			interrupts = <36 2 0 0>;
+		qman: qman at 318000 {
+			/* Commented out, use default allocation */
+			/* fsl,qman-fqd = <0x0 0x20000000 0x0 0x01000000>; */
+			/* fsl,qman-pfdr = <0x0 0x21000000 0x0 0x01000000>; */
 		};
 
-		serial2: serial at 11d500 {
-			cell-index = <2>;
-			device_type = "serial";
-			compatible = "ns16550";
-			reg = <0x11d500 0x100>;
-			clock-frequency = <0>;
-			interrupts = <37 2 0 0>;
+		bman: bman at 31a000 {
+			/* Same as fsl,qman-*, use default allocation */
+			/* fsl,bman-fbpr = <0x0 0x22000000 0x0 0x01000000>; */
 		};
 
-		serial3: serial at 11d600 {
-			cell-index = <3>;
-			device_type = "serial";
-			compatible = "ns16550";
-			reg = <0x11d600 0x100>;
-			clock-frequency = <0>;
-			interrupts = <37 2 0 0>;
-		};
-
-		gpio0: gpio at 130000 {
-			compatible = "fsl,p3041-gpio", "fsl,qoriq-gpio";
-			reg = <0x130000 0x1000>;
-			interrupts = <55 2 0 0>;
-			#gpio-cells = <2>;
-			gpio-controller;
-		};
-
-		usb0: usb at 210000 {
-			compatible = "fsl,p3041-usb2-mph",
-					"fsl,mpc85xx-usb2-mph", "fsl-usb2-mph";
-			reg = <0x210000 0x1000>;
-			#address-cells = <1>;
-			#size-cells = <0>;
-			interrupts = <44 0x2 0 0>;
-			phy_type = "utmi";
-			port0;
-		};
-
-		usb1: usb at 211000 {
-			compatible = "fsl,p3041-usb2-dr",
-					"fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
-			reg = <0x211000 0x1000>;
-			#address-cells = <1>;
-			#size-cells = <0>;
-			interrupts = <45 0x2 0 0>;
-			dr_mode = "host";
-			phy_type = "utmi";
-		};
-
-		sata at 220000 {
-			compatible = "fsl,p3041-sata", "fsl,pq-sata-v2";
-			reg = <0x220000 0x1000>;
-			interrupts = <68 0x2 0 0>;
-		};
-
-		sata at 221000 {
-			compatible = "fsl,p3041-sata", "fsl,pq-sata-v2";
-			reg = <0x221000 0x1000>;
-			interrupts = <69 0x2 0 0>;
-		};
-
-		crypto: crypto at 300000 {
-			compatible = "fsl,sec-v4.2", "fsl,sec-v4.0";
-			#address-cells = <1>;
-			#size-cells = <1>;
-			reg = <0x300000 0x10000>;
-			ranges = <0 0x300000 0x10000>;
-			interrupts = <92 2 0 0>;
-
-			sec_jr0: jr at 1000 {
-				compatible = "fsl,sec-v4.2-job-ring",
-					     "fsl,sec-v4.0-job-ring";
-				reg = <0x1000 0x1000>;
-				interrupts = <88 2 0 0>;
+		fman0: fman at 400000 {
+			enet0: ethernet at e0000 {
+				tbi-handle = <&tbi0>;
+				phy-handle = <&phy_rgmii_0>;
+				phy-connection-type = "rgmii";
 			};
 
-			sec_jr1: jr at 2000 {
-				compatible = "fsl,sec-v4.2-job-ring",
-					     "fsl,sec-v4.0-job-ring";
-				reg = <0x2000 0x1000>;
-				interrupts = <89 2 0 0>;
+			mdio0: mdio at e1120 {
+				tbi0: tbi-phy at 8 {
+					reg = <0x8>;
+					device_type = "tbi-phy";
+				};
+
+				/*
+				 * Virtual MDIO for the two on-board RGMII
+				 * ports.  The fsl,hydra-mdio-muxval property
+				 * is already correct.
+				 */
+				hydra_mdio_rgmii: hydra-mdio-rgmii {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					compatible = "fsl,hydra-mdio";
+					fsl,mdio-handle = <&mdio0>;
+					fsl,hydra-mdio-muxval = <0x00>;
+					status = "disabled";
+
+					phy_rgmii_0: ethernet-phy at 0 {
+						reg = <0x0>;
+					};
+					phy_rgmii_1: ethernet-phy at 1 {
+						reg = <0x1>;
+					};
+				};
+
+				/*
+				 * Virtual MDIO for the four-port SGMII card.
+				 * The fsl,hydra-mdio-muxval property will be
+				 * fixed-up by U-Boot based on the slot that
+				 * the SGMII card is in.
+				 *
+				 * Note: we do not support DTSEC5 connected to
+				 * SGMII, so this is the only SGMII node.
+				 */
+				hydra_mdio_sgmii: hydra-mdio-sgmii {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					compatible = "fsl,hydra-mdio";
+					fsl,mdio-handle = <&mdio0>;
+					fsl,hydra-mdio-muxval = <0x00>;
+					status = "disabled";
+
+					phy_sgmii_1c: ethernet-phy at 1c {
+						reg = <0x1c>;
+					};
+					phy_sgmii_1d: ethernet-phy at 1d {
+						reg = <0x1d>;
+					};
+					phy_sgmii_1e: ethernet-phy at 1e {
+						reg = <0x1e>;
+					};
+					phy_sgmii_1f: ethernet-phy at 1f {
+						reg = <0x1f>;
+					};
+				};
 			};
 
-			sec_jr2: jr at 3000 {
-				compatible = "fsl,sec-v4.2-job-ring",
-					     "fsl,sec-v4.0-job-ring";
-				reg = <0x3000 0x1000>;
-				interrupts = <90 2 0 0>;
+			enet1: ethernet at e2000 {
+				tbi-handle = <&tbi1>;
+				phy-handle = <&phy_sgmii_1d>;
+				phy-connection-type = "sgmii";
 			};
 
-			sec_jr3: jr at 4000 {
-				compatible = "fsl,sec-v4.2-job-ring",
-					     "fsl,sec-v4.0-job-ring";
-				reg = <0x4000 0x1000>;
-				interrupts = <91 2 0 0>;
+			mdio at e3120 {
+				tbi1: tbi-phy at 8 {
+					reg = <8>;
+					device_type = "tbi-phy";
+				};
 			};
 
-			rtic at 6000 {
-				compatible = "fsl,sec-v4.2-rtic",
-					     "fsl,sec-v4.0-rtic";
+			enet2: ethernet at e4000 {
+				tbi-handle = <&tbi2>;
+				phy-handle = <&phy_sgmii_1e>;
+				phy-connection-type = "sgmii";
+			};
+
+			mdio at e5120 {
+				tbi2: tbi-phy at 8 {
+					reg = <8>;
+					device_type = "tbi-phy";
+				};
+			};
+
+			enet3: ethernet at e6000 {
+				tbi-handle = <&tbi3>;
+				phy-handle = <&phy_sgmii_1f>;
+				phy-connection-type = "sgmii";
+			};
+
+			mdio at e7120 {
 				#address-cells = <1>;
-				#size-cells = <1>;
-				reg = <0x6000 0x100>;
-				ranges = <0x0 0x6100 0xe00>;
+				#size-cells = <0>;
+				compatible = "fsl,fman-tbi";
+				reg = <0xe7120 0xee0>;
+				interrupts = <100 1 0 0>;
 
-				rtic_a: rtic-a at 0 {
-					compatible = "fsl,sec-v4.2-rtic-memory",
-						     "fsl,sec-v4.0-rtic-memory";
-					reg = <0x00 0x20 0x100 0x80>;
+				tbi3: tbi-phy at 8 {
+					reg = <8>;
+					device_type = "tbi-phy";
+				};
+			};
+
+			enet4: ethernet at e8000 {
+				tbi-handle = <&tbi4>;
+				phy-handle = <&phy_rgmii_1>;
+				phy-connection-type = "rgmii";
+			};
+
+			mdio at e9120 {
+				tbi4: tbi-phy at 8 {
+					reg = <8>;
+					device_type = "tbi-phy";
+				};
+			};
+
+			enet5: ethernet at f0000 {
+				/*
+				 * phy-handle will be updated by U-Boot to
+				 * reflect the actual slot the XAUI card is in.
+				 */
+				phy-handle = <&phy_xgmii_1>;
+				phy-connection-type = "xgmii";
+			};
+
+			/*
+			 * We only support one XAUI card, so the MDIO muxing
+			 * is set by U-Boot, and Linux never touches it.
+			 * Therefore, we don't need a virtual MDIO node.
+			 * However, the phy address depends on the slot, so
+			 * only one of the ethernet-phy nodes below will be
+			 * used.
+			 */
+			hydra_mdio_xgmii: mdio at f1000 {
+				status = "disabled";
+
+				/* XAUI card in slot 1 */
+				phy_xgmii_1: ethernet-phy at 4 {
+					reg = <0x4>;
 				};
 
-				rtic_b: rtic-b at 20 {
-					compatible = "fsl,sec-v4.2-rtic-memory",
-						     "fsl,sec-v4.0-rtic-memory";
-					reg = <0x20 0x20 0x200 0x80>;
-				};
-
-				rtic_c: rtic-c at 40 {
-					compatible = "fsl,sec-v4.2-rtic-memory",
-						     "fsl,sec-v4.0-rtic-memory";
-					reg = <0x40 0x20 0x300 0x80>;
-				};
-
-				rtic_d: rtic-d at 60 {
-					compatible = "fsl,sec-v4.2-rtic-memory",
-						     "fsl,sec-v4.0-rtic-memory";
-					reg = <0x60 0x20 0x500 0x80>;
+				/* XAUI card in slot 2 */
+				phy_xgmii_2: ethernet-phy at 0 {
+					reg = <0x0>;
 				};
 			};
 		};
+	};
 
-		sec_mon: sec_mon at 314000 {
-			compatible = "fsl,sec-v4.2-mon", "fsl,sec-v4.0-mon";
-			reg = <0x314000 0x1000>;
-			interrupts = <93 2 0 0>;
+	rapidio at ffe0c0000 {
+		reg = <0xf 0xfe0c0000 0 0x11000>;
+
+		port1 {
+			ranges = <0 0 0xc 0x20000000 0 0x10000000>;
+		};
+		port2 {
+			ranges = <0 0 0xc 0x30000000 0 0x10000000>;
 		};
 	};
 
 	localbus at ffe124000 {
-		compatible = "fsl,p3041-elbc", "fsl,elbc", "simple-bus";
 		reg = <0xf 0xfe124000 0 0x1000>;
-		interrupts = <25 2 0 0>;
-		#address-cells = <2>;
-		#size-cells = <1>;
-
-		ranges = <0 0 0xf 0xe8000000 0x08000000
-			  3 0 0xf 0xffdf0000 0x00008000>;
+		ranges = <0 0 0xf 0xb8000000 0x04000000>;
 
 		flash at 0,0 {
 			compatible = "cfi-flash";
-			reg = <0 0 0x08000000>;
+			/*
+                         * Map 64Mb of 128MB NOR flash memory. Since highest
+                         * line of address of NOR flash memory are set by
+                         * FPGA, memory are divided into two pages equal to
+                         * 64MB. One of the pages can be accessed at once.
+                         */
+			reg = <0 0 0x04000000>;
 			bank-width = <2>;
 			device-width = <2>;
 		};
 
+		nand at 2,0 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "fsl,elbc-fcm-nand";
+			reg = <0x2 0x0 0x40000>;
+
+			partition at 0 {
+				label = "NAND U-Boot Image";
+				reg = <0x0 0x02000000>;
+				read-only;
+			};
+
+			partition at 2000000 {
+				label = "NAND Root File System";
+				reg = <0x02000000 0x10000000>;
+			};
+
+			partition at 12000000 {
+				label = "NAND Compressed RFS Image";
+				reg = <0x12000000 0x08000000>;
+			};
+
+			partition at 1a000000 {
+				label = "NAND Linux Kernel Image";
+				reg = <0x1a000000 0x04000000>;
+			};
+
+			partition at 1e000000 {
+				label = "NAND DTB Image";
+				reg = <0x1e000000 0x01000000>;
+			};
+
+			partition at 1f000000 {
+				label = "NAND Writable User area";
+				reg = <0x1f000000 0x21000000>;
+			};
+		};
+
 		board-control at 3,0 {
-			compatible = "fsl,p3041ds-pixis";
-			reg = <3 0 0x20>;
+			compatible = "fsl,p3041ds-fpga", "fsl,fpga-ngpixis";
+			reg = <3 0 0x30>;
 		};
 	};
 
 	pci0: pcie at ffe200000 {
-		compatible = "fsl,p3041-pcie", "fsl,qoriq-pcie-v2.2";
-		device_type = "pci";
-		#size-cells = <2>;
-		#address-cells = <3>;
 		reg = <0xf 0xfe200000 0 0x1000>;
-		bus-range = <0x0 0xff>;
-		ranges = <0x02000000 0 0xe0000000 0xc 0x00000000 0x0 0x20000000
-			  0x01000000 0 0x00000000 0xf 0xf8000000 0x0 0x00010000>;
-		clock-frequency = <0x1fca055>;
-		fsl,msi = <&msi0>;
-		interrupts = <16 2 1 15>;
+		ranges = <0x02000000 0 0x80000000 0x0 0x80000000 0x0 0x10000000
+			  0x01000000 0 0x00000000 0x0 0xff000000 0x0 0x00010000>;
 		pcie at 0 {
-			reg = <0 0 0 0 0>;
-			#interrupt-cells = <1>;
-			#size-cells = <2>;
-			#address-cells = <3>;
-			device_type = "pci";
-			interrupts = <16 2 1 15>;
-			interrupt-map-mask = <0xf800 0 0 7>;
-			interrupt-map = <
-				/* IDSEL 0x0 */
-				0000 0 0 1 &mpic 40 1 0 0
-				0000 0 0 2 &mpic 1 1 0 0
-				0000 0 0 3 &mpic 2 1 0 0
-				0000 0 0 4 &mpic 3 1 0 0
-				>;
-			ranges = <0x02000000 0 0xe0000000
-				  0x02000000 0 0xe0000000
-				  0 0x20000000
+			ranges = <0x02000000 0 0x80000000
+				  0x02000000 0 0x80000000
+				  0 0x10000000
 
 				  0x01000000 0 0x00000000
-				  0x01000000 0 0x00000000
+				  0x01000000 0 0xff000000
 				  0 0x00010000>;
 		};
 	};
 
 	pci1: pcie at ffe201000 {
-		compatible = "fsl,p3041-pcie", "fsl,qoriq-pcie-v2.2";
-		device_type = "pci";
-		#size-cells = <2>;
-		#address-cells = <3>;
 		reg = <0xf 0xfe201000 0 0x1000>;
-		bus-range = <0 0xff>;
-		ranges = <0x02000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000
-			  0x01000000 0x0 0x00000000 0xf 0xf8010000 0x0 0x00010000>;
-		clock-frequency = <0x1fca055>;
-		fsl,msi = <&msi1>;
-		interrupts = <16 2 1 14>;
+		ranges = <0x02000000 0x0 0x90000000 0x0 0x90000000 0x0 0x10000000
+			  0x01000000 0x0 0x00000000 0x0 0xff010000 0x0 0x00010000>;
 		pcie at 0 {
-			reg = <0 0 0 0 0>;
-			#interrupt-cells = <1>;
-			#size-cells = <2>;
-			#address-cells = <3>;
-			device_type = "pci";
-			interrupts = <16 2 1 14>;
-			interrupt-map-mask = <0xf800 0 0 7>;
-			interrupt-map = <
-				/* IDSEL 0x0 */
-				0000 0 0 1 &mpic 41 1 0 0
-				0000 0 0 2 &mpic 5 1 0 0
-				0000 0 0 3 &mpic 6 1 0 0
-				0000 0 0 4 &mpic 7 1 0 0
-				>;
-			ranges = <0x02000000 0 0xe0000000
-				  0x02000000 0 0xe0000000
-				  0 0x20000000
+			ranges = <0x02000000 0 0x90000000
+				  0x02000000 0 0x90000000
+				  0 0x10000000
 
 				  0x01000000 0 0x00000000
-				  0x01000000 0 0x00000000
+				  0x01000000 0 0xff010000
 				  0 0x00010000>;
 		};
 	};
 
 	pci2: pcie at ffe202000 {
-		compatible = "fsl,p3041-pcie", "fsl,qoriq-pcie-v2.2";
-		device_type = "pci";
-		#size-cells = <2>;
-		#address-cells = <3>;
 		reg = <0xf 0xfe202000 0 0x1000>;
-		bus-range = <0x0 0xff>;
-		ranges = <0x02000000 0 0xe0000000 0xc 0x40000000 0 0x20000000
-			  0x01000000 0 0x00000000 0xf 0xf8020000 0 0x00010000>;
-		clock-frequency = <0x1fca055>;
-		fsl,msi = <&msi2>;
-		interrupts = <16 2 1 13>;
+		ranges = <0x02000000 0 0xa0000000 0x0 0xa0000000 0 0x10000000
+			  0x01000000 0 0x00000000 0x0 0xff020000 0 0x00010000>;
 		pcie at 0 {
-			reg = <0 0 0 0 0>;
-			#interrupt-cells = <1>;
-			#size-cells = <2>;
-			#address-cells = <3>;
-			device_type = "pci";
-			interrupts = <16 2 1 13>;
-			interrupt-map-mask = <0xf800 0 0 7>;
-			interrupt-map = <
-				/* IDSEL 0x0 */
-				0000 0 0 1 &mpic 42 1 0 0
-				0000 0 0 2 &mpic 9 1 0 0
-				0000 0 0 3 &mpic 10 1 0 0
-				0000 0 0 4 &mpic 11 1 0 0
-				>;
-			ranges = <0x02000000 0 0xe0000000
-				  0x02000000 0 0xe0000000
-				  0 0x20000000
+			ranges = <0x02000000 0 0xa0000000
+				  0x02000000 0 0xa0000000
+				  0 0x10000000
 
 				  0x01000000 0 0x00000000
-				  0x01000000 0 0x00000000
+				  0x01000000 0 0xff020000
 				  0 0x00010000>;
 		};
 	};
 
 	pci3: pcie at ffe203000 {
-		compatible = "fsl,p3041-pcie", "fsl,qoriq-pcie-v2.2";
-		device_type = "pci";
-		#size-cells = <2>;
-		#address-cells = <3>;
 		reg = <0xf 0xfe203000 0 0x1000>;
-		bus-range = <0x0 0xff>;
-		ranges = <0x02000000 0 0xe0000000 0xc 0x60000000 0 0x20000000
-			  0x01000000 0 0x00000000 0xf 0xf8030000 0 0x00010000>;
-		clock-frequency = <0x1fca055>;
-		fsl,msi = <&msi2>;
-		interrupts = <16 2 1 12>;
+		ranges = <0x02000000 0 0xb0000000 0x0 0xb0000000 0 0x08000000
+			  0x01000000 0 0x00000000 0x0 0xff030000 0 0x00010000>;
 		pcie at 0 {
-			reg = <0 0 0 0 0>;
-			#interrupt-cells = <1>;
-			#size-cells = <2>;
-			#address-cells = <3>;
-			device_type = "pci";
-			interrupts = <16 2 1 12>;
-			interrupt-map-mask = <0xf800 0 0 7>;
-			interrupt-map = <
-				/* IDSEL 0x0 */
-				0000 0 0 1 &mpic 43 1 0 0
-				0000 0 0 2 &mpic 0 1 0 0
-				0000 0 0 3 &mpic 4 1 0 0
-				0000 0 0 4 &mpic 8 1 0 0
-				>;
-			ranges = <0x02000000 0 0xe0000000
-				  0x02000000 0 0xe0000000
-				  0 0x20000000
+			ranges = <0x02000000 0 0xb0000000
+				  0x02000000 0 0xb0000000
+				  0 0x08000000
 
 				  0x01000000 0 0x00000000
-				  0x01000000 0 0x00000000
+				  0x01000000 0 0xff030000
 				  0 0x00010000>;
 		};
 	};
+
+	fsl,dpaa {
+		compatible = "fsl,p3041-dpaa", "fsl,dpaa";
+
+		ethernet at 0 {
+			compatible = "fsl,p3041-dpa-ethernet", "fsl,dpa-ethernet";
+			fsl,qman-channel = <&qpool1>;
+			fsl,fman-mac = <&enet0>;
+			status="okay";
+		};
+		ethernet at 1 {
+			compatible = "fsl,p3041-dpa-ethernet", "fsl,dpa-ethernet";
+			fsl,qman-channel = <&qpool1>;
+			fsl,fman-mac = <&enet1>;
+			status = "disabled";
+		};
+		ethernet at 2 {
+			compatible = "fsl,p3041-dpa-ethernet", "fsl,dpa-ethernet";
+			fsl,qman-channel = <&qpool1>;
+			fsl,fman-mac = <&enet2>;
+			status = "disabled";
+		};
+		ethernet at 3 {
+			compatible = "fsl,p3041-dpa-ethernet", "fsl,dpa-ethernet";
+			fsl,qman-channel = <&qpool1>;
+			fsl,fman-mac = <&enet3>;
+			status = "disabled";
+		};
+		ethernet at 4 {
+			compatible = "fsl,p3041-dpa-ethernet", "fsl,dpa-ethernet";
+			fsl,qman-channel = <&qpool1>;
+			fsl,fman-mac = <&enet4>;
+			status = "okay";
+		};
+		ethernet at 5 {
+			compatible = "fsl,p3041-dpa-ethernet", "fsl,dpa-ethernet";
+			fsl,qman-channel = <&qpool1>;
+			fsl,fman-mac = <&enet5>;
+			status = "disabled";
+		};
+	};
+
+	chosen {
+		stdin = "serial0";
+		stdout = "serial0";
+	};
 };
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/fdt/dts/p3041si.dtsi
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/boot/fdt/dts/p3041si.dtsi	Wed Jul 25 16:45:04 2012 +0300
@@ -0,0 +1,1339 @@
+/*
+ * P3041 Silicon Device Tree Source
+ *
+ * Copyright 2010-2011 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/* $FreeBSD: head/sys/boot/fdt/dts/p3041si.dtsi 236024 2012-05-25 20:43:38Z raj $ */
+
+/dts-v1/;
+
+/ {
+	compatible = "fsl,P3041";
+	#address-cells = <2>;
+	#size-cells = <2>;
+	interrupt-parent = <&mpic>;
+
+	aliases {
+		ccsr = &soc;
+		dcsr = &dcsr;
+
+		ethernet0 = &enet0;
+		ethernet1 = &enet1;
+		ethernet2 = &enet2;
+		ethernet3 = &enet3;
+		ethernet4 = &enet4;
+		ethernet5 = &enet5;
+		serial0 = &serial0;
+		serial1 = &serial1;
+		serial2 = &serial2;
+		serial3 = &serial3;
+		pci0 = &pci0;
+		pci1 = &pci1;
+		pci2 = &pci2;
+		pci3 = &pci3;
+		usb0 = &usb0;
+		usb1 = &usb1;
+		dma0 = &dma0;
+		dma1 = &dma1;
+		bman = &bman;
+		qman = &qman;
+		pme = &pme;
+		rman = &rman;
+		sdhc = &sdhc;
+		msi0 = &msi0;
+		msi1 = &msi1;
+		msi2 = &msi2;
+
+		crypto = &crypto;
+		sec_jr0 = &sec_jr0;
+		sec_jr1 = &sec_jr1;
+		sec_jr2 = &sec_jr2;
+		sec_jr3 = &sec_jr3;
+		rtic_a = &rtic_a;
+		rtic_b = &rtic_b;
+		rtic_c = &rtic_c;
+		rtic_d = &rtic_d;
+		sec_mon = &sec_mon;
+
+		fman0 = &fman0;
+		fman0_oh0 = &fman0_oh0;
+		fman0_oh1 = &fman0_oh1;
+		fman0_oh2 = &fman0_oh2;
+		fman0_oh3 = &fman0_oh3;
+		fman0_oh4 = &fman0_oh4;
+		fman0_oh5 = &fman0_oh5;
+		fman0_oh6 = &fman0_oh6;
+		fman0_rx0 = &fman0_rx0;
+		fman0_rx1 = &fman0_rx1;
+		fman0_rx2 = &fman0_rx2;
+		fman0_rx3 = &fman0_rx3;
+		fman0_rx4 = &fman0_rx4;
+		fman0_rx5 = &fman0_rx5;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu0: PowerPC,e500mc at 0 {
+			device_type = "cpu";
+			reg = <0>;
+			bus-frequency = <749999996>;
+			next-level-cache = <&L2_0>;
+			L2_0: l2-cache {
+				next-level-cache = <&cpc>;
+			};
+		};
+		cpu1: PowerPC,e500mc at 1 {
+			device_type = "cpu";
+			reg = <1>;
+			next-level-cache = <&L2_1>;
+			L2_1: l2-cache {
+				next-level-cache = <&cpc>;
+			};
+		};
+		cpu2: PowerPC,e500mc at 2 {
+			device_type = "cpu";
+			reg = <2>;
+			next-level-cache = <&L2_2>;
+			L2_2: l2-cache {
+				next-level-cache = <&cpc>;
+			};
+		};
+		cpu3: PowerPC,e500mc at 3 {
+			device_type = "cpu";
+			reg = <3>;
+			next-level-cache = <&L2_3>;
+			L2_3: l2-cache {
+				next-level-cache = <&cpc>;
+			};
+		};
+	};
+
+	dcsr: dcsr at f00000000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "fsl,dcsr", "simple-bus";
+
+		dcsr-epu at 0 {
+			compatible = "fsl,dcsr-epu";
+			interrupts = <52 2 0 0
+				      84 2 0 0
+				      85 2 0 0>;
+			interrupt-parent = <&mpic>;
+			reg = <0x0 0x1000>;
+		};
+		dcsr-npc {
+			compatible = "fsl,dcsr-npc";
+			reg = <0x1000 0x1000 0x1000000 0x8000>;
+		};
+		dcsr-nxc at 2000 {
+			compatible = "fsl,dcsr-nxc";
+			reg = <0x2000 0x1000>;
+		};
+		dcsr-corenet {
+			compatible = "fsl,dcsr-corenet";
+			reg = <0x8000 0x1000 0xB0000 0x1000>;
+		};
+		dcsr-dpaa at 9000 {
+			compatible = "fsl,p43041-dcsr-dpaa", "fsl,dcsr-dpaa";
+			reg = <0x9000 0x1000>;
+		};
+		dcsr-ocn at 11000 {
+			compatible = "fsl,p43041-dcsr-ocn", "fsl,dcsr-ocn";
+			reg = <0x11000 0x1000>;
+		};
+		dcsr-ddr at 12000 {
+			compatible = "fsl,dcsr-ddr";
+			dev-handle = <&ddr>;
+			reg = <0x12000 0x1000>;
+		};
+		dcsr-nal at 18000 {
+			compatible = "fsl,p43041-dcsr-nal", "fsl,dcsr-nal";
+			reg = <0x18000 0x1000>;
+		};
+		dcsr-rcpm at 22000 {
+			compatible = "fsl,p43041-dcsr-rcpm", "fsl,dcsr-rcpm";
+			reg = <0x22000 0x1000>;
+		};
+		dcsr-cpu-sb-proxy at 40000 {
+			compatible = "fsl,dcsr-e500mc-sb-proxy", "fsl,dcsr-cpu-sb-proxy";
+			cpu-handle = <&cpu0>;
+			reg = <0x40000 0x1000>;
+		};
+		dcsr-cpu-sb-proxy at 41000 {
+			compatible = "fsl,dcsr-e500mc-sb-proxy", "fsl,dcsr-cpu-sb-proxy";
+			cpu-handle = <&cpu1>;
+			reg = <0x41000 0x1000>;
+		};
+		dcsr-cpu-sb-proxy at 42000 {
+			compatible = "fsl,dcsr-e500mc-sb-proxy", "fsl,dcsr-cpu-sb-proxy";
+			cpu-handle = <&cpu2>;
+			reg = <0x42000 0x1000>;
+		};
+		dcsr-cpu-sb-proxy at 43000 {
+			compatible = "fsl,dcsr-e500mc-sb-proxy", "fsl,dcsr-cpu-sb-proxy";
+			cpu-handle = <&cpu3>;
+			reg = <0x43000 0x1000>;
+		};
+	};
+
+	bman-portals at ff4000000 {
+		#address-cells = <0x1>;
+		#size-cells = <0x1>;
+		compatible = "bman-portals";
+		ranges = <0x0 0xf 0xfde00000 0x200000>;
+		bman-portal at 0 {
+			cell-index = <0x0>;
+			compatible = "fsl,p3041-bman-portal", "fsl,bman-portal";
+			reg = <0x0 0x4000 0x100000 0x1000>;
+			interrupts = <105 2 0 0>;
+		};
+		bman-portal at 4000 {
+			cell-index = <0x1>;
+			compatible = "fsl,p3041-bman-portal", "fsl,bman-portal";
+			reg = <0x4000 0x4000 0x101000 0x1000>;
+			interrupts = <107 2 0 0>;
+		};
+		bman-portal at 8000 {
+			cell-index = <2>;
+			compatible = "fsl,p3041-bman-portal", "fsl,bman-portal";
+			reg = <0x8000 0x4000 0x102000 0x1000>;
+			interrupts = <109 2 0 0>;
+		};
+		bman-portal at c000 {
+			cell-index = <0x3>;
+			compatible = "fsl,p3041-bman-portal", "fsl,bman-portal";
+			reg = <0xc000 0x4000 0x103000 0x1000>;
+			interrupts = <111 2 0 0>;
+		};
+		bman-portal at 10000 {
+			cell-index = <0x4>;
+			compatible = "fsl,p3041-bman-portal", "fsl,bman-portal";
+			reg = <0x10000 0x4000 0x104000 0x1000>;
+			interrupts = <113 2 0 0>;
+		};
+		bman-portal at 14000 {
+			cell-index = <0x5>;
+			compatible = "fsl,p3041-bman-portal", "fsl,bman-portal";
+			reg = <0x14000 0x4000 0x105000 0x1000>;
+			interrupts = <115 2 0 0>;
+		};
+		bman-portal at 18000 {
+			cell-index = <0x6>;
+			compatible = "fsl,p3041-bman-portal", "fsl,bman-portal";
+			reg = <0x18000 0x4000 0x106000 0x1000>;
+			interrupts = <117 2 0 0>;
+		};
+		bman-portal at 1c000 {
+			cell-index = <0x7>;
+			compatible = "fsl,p3041-bman-portal", "fsl,bman-portal";
+			reg = <0x1c000 0x4000 0x107000 0x1000>;
+			interrupts = <119 2 0 0>;
+		};
+		bman-portal at 20000 {
+			cell-index = <0x8>;
+			compatible = "fsl,p3041-bman-portal", "fsl,bman-portal";
+			reg = <0x20000 0x4000 0x108000 0x1000>;
+			interrupts = <121 2 0 0>;
+		};
+		bman-portal at 24000 {
+			cell-index = <0x9>;
+			compatible = "fsl,p3041-bman-portal", "fsl,bman-portal";
+			reg = <0x24000 0x4000 0x109000 0x1000>;
+			interrupts = <123 2 0 0>;
+		};
+
+		buffer-pool at 0 {
+			compatible = "fsl,p3041-bpool", "fsl,bpool";
+			fsl,bpid = <0>;
+			fsl,bpool-cfg = <0 0x100 0 1 0 0x100>;
+		};
+	};
+
+	qman-portals at ff4200000 {
+		#address-cells = <0x1>;
+		#size-cells = <0x1>;
+		compatible = "qman-portals";
+		ranges = <0x0 0xf 0xfdc00000 0x200000>;
+		qportal0: qman-portal at 0 {
+			cell-index = <0x0>;
+			compatible = "fsl,p3041-qman-portal", "fsl,qman-portal";
+			reg = <0x0 0x4000 0x100000 0x1000>;
+			interrupts = <104 0x2 0 0>;
+			fsl,qman-channel-id = <0x0>;
+		};
+
+		qportal1: qman-portal at 4000 {
+			cell-index = <0x1>;
+			compatible = "fsl,p3041-qman-portal", "fsl,qman-portal";
+			reg = <0x4000 0x4000 0x101000 0x1000>;
+			interrupts = <106 0x2 0 0>;
+			fsl,qman-channel-id = <0x1>;
+		};
+
+		qportal2: qman-portal at 8000 {
+			cell-index = <0x2>;
+			compatible = "fsl,p3041-qman-portal", "fsl,qman-portal";
+			reg = <0x8000 0x4000 0x102000 0x1000>;
+			interrupts = <108 0x2 0 0>;
+			fsl,qman-channel-id = <0x2>;
+		};
+
+		qportal3: qman-portal at c000 {
+			cell-index = <0x3>;
+			compatible = "fsl,p3041-qman-portal", "fsl,qman-portal";
+			reg = <0xc000 0x4000 0x103000 0x1000>;
+			interrupts = <110 0x2 0 0>;
+			fsl,qman-channel-id = <0x3>;
+		};
+
+		qportal4: qman-portal at 10000 {
+			cell-index = <0x4>;
+			compatible = "fsl,p3041-qman-portal", "fsl,qman-portal";
+			reg = <0x10000 0x4000 0x104000 0x1000>;
+			interrupts = <112 0x2 0 0>;
+			fsl,qman-channel-id = <0x4>;
+		};
+
+		qportal5: qman-portal at 14000 {
+			cell-index = <0x5>;
+			compatible = "fsl,p3041-qman-portal", "fsl,qman-portal";
+			reg = <0x14000 0x4000 0x105000 0x1000>;
+			interrupts = <114 0x2 0 0>;
+			fsl,qman-channel-id = <0x5>;
+		};
+
+		qportal6: qman-portal at 18000 {
+			cell-index = <0x6>;
+			compatible = "fsl,p3041-qman-portal", "fsl,qman-portal";
+			reg = <0x18000 0x4000 0x106000 0x1000>;
+			interrupts = <116 0x2 0 0>;
+			fsl,qman-channel-id = <0x6>;
+		};
+
+		qportal7: qman-portal at 1c000 {
+			cell-index = <0x7>;
+			compatible = "fsl,p3041-qman-portal", "fsl,qman-portal";
+			reg = <0x1c000 0x4000 0x107000 0x1000>;
+			interrupts = <118 0x2 0 0>;
+			fsl,qman-channel-id = <0x7>;
+		};
+
+		qportal8: qman-portal at 20000 {
+			cell-index = <0x8>;
+			compatible = "fsl,p3041-qman-portal", "fsl,qman-portal";
+			reg = <0x20000 0x4000 0x108000 0x1000>;
+			interrupts = <120 0x2 0 0>;
+			fsl,qman-channel-id = <0x8>;
+		};
+
+		qportal9: qman-portal at 24000 {
+			cell-index = <0x9>;
+			compatible = "fsl,p3041-qman-portal", "fsl,qman-portal";
+			reg = <0x24000 0x4000 0x109000 0x1000>;
+			interrupts = <122 0x2 0 0>;
+			fsl,qman-channel-id = <0x9>;
+		};
+
+		qpool1: qman-pool at 1 {
+			cell-index = <1>;
+			compatible = "fsl,p3041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x21>;
+		};
+
+		qpool2: qman-pool at 2 {
+			cell-index = <2>;
+			compatible = "fsl,p3041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x22>;
+		};
+
+		qpool3: qman-pool at 3 {
+			cell-index = <3>;
+			compatible = "fsl,p3041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x23>;
+		};
+
+		qpool4: qman-pool at 4 {
+			cell-index = <4>;
+			compatible = "fsl,p3041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x24>;
+		};
+
+		qpool5: qman-pool at 5 {
+			cell-index = <5>;
+			compatible = "fsl,p3041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x25>;
+		};
+
+		qpool6: qman-pool at 6 {
+			cell-index = <6>;
+			compatible = "fsl,p3041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x26>;
+		};
+
+		qpool7: qman-pool at 7 {
+			cell-index = <7>;
+			compatible = "fsl,p3041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x27>;
+		};
+
+		qpool8: qman-pool at 8 {
+			cell-index = <8>;
+			compatible = "fsl,p3041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x28>;
+		};
+
+		qpool9: qman-pool at 9 {
+			cell-index = <9>;
+			compatible = "fsl,p3041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x29>;
+		};
+
+		qpool10: qman-pool at 10 {
+			cell-index = <10>;
+			compatible = "fsl,p3041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x2a>;
+		};
+
+		qpool11: qman-pool at 11 {
+			cell-index = <11>;
+			compatible = "fsl,p3041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x2b>;
+		};
+
+		qpool12: qman-pool at 12 {
+			cell-index = <12>;
+			compatible = "fsl,p3041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x2c>;
+		};
+
+		qpool13: qman-pool at 13 {
+			cell-index = <13>;
+			compatible = "fsl,p3041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x2d>;
+		};
+
+		qpool14: qman-pool at 14 {
+			cell-index = <14>;
+			compatible = "fsl,p3041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x2e>;
+		};
+
+		qpool15: qman-pool at 15 {
+			cell-index = <15>;
+			compatible = "fsl,p3041-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x2f>;
+		};
+	};
+
+	soc: soc at ffe000000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		device_type = "soc";
+		compatible = "simple-bus";
+		
+		bus-frequency = <0>;	// Filled out by kernel.
+		
+		ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
+		reg = <0xf 0xfe000000 0 0x00001000>;
+
+		soc-sram-error {
+			compatible = "fsl,soc-sram-error";
+			interrupts = <16 2 1 29>;
+		};
+
+		corenet-law at 0 {
+			compatible = "fsl,corenet-law";
+			reg = <0x0 0x1000>;
+			fsl,num-laws = <32>;
+		};
+
+		ddr: memory-controller at 8000 {
+			compatible = "fsl,qoriq-memory-controller-v4.5", "fsl,qoriq-memory-controller";
+			reg = <0x8000 0x1000>;
+			interrupts = <16 2 1 23>;
+		};
+
+		cpc: l3-cache-controller at 10000 {
+			compatible = "fsl,p3041-l3-cache-controller", "fsl,p4080-l3-cache-controller", "cache";
+			reg = <0x10000 0x1000>;
+			interrupts = <16 2 1 27>;
+		};
+
+		corenet-cf at 18000 {
+			compatible = "fsl,corenet-cf";
+			reg = <0x18000 0x1000>;
+			interrupts = <16 2 1 31>;
+			fsl,ccf-num-csdids = <32>;
+			fsl,ccf-num-snoopids = <32>;
+		};
+
+		iommu at 20000 {
+			compatible = "fsl,pamu-v1.0", "fsl,pamu";
+			reg = <0x20000 0x4000>;
+			interrupts = <
+				24 2 0 0
+				16 2 1 30>;
+		};
+
+		mpic: pic at 40000 {
+			clock-frequency = <0>;
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <4>;
+			reg = <0x40000 0x40000>;
+			compatible = "fsl,mpic", "chrp,open-pic";
+			device_type = "open-pic";
+		};
+
+		msi0: msi at 41600 {
+			compatible = "fsl,mpic-msi";
+			reg = <0x41600 0x200>;
+			msi-available-ranges = <0 0x100>;
+			interrupts = <
+				0xe0 0 0 0
+				0xe1 0 0 0
+				0xe2 0 0 0
+				0xe3 0 0 0
+				0xe4 0 0 0
+				0xe5 0 0 0
+				0xe6 0 0 0
+				0xe7 0 0 0>;
+		};
+
+		msi1: msi at 41800 {
+			compatible = "fsl,mpic-msi";
+			reg = <0x41800 0x200>;
+			msi-available-ranges = <0 0x100>;
+			interrupts = <
+				0xe8 0 0 0
+				0xe9 0 0 0
+				0xea 0 0 0
+				0xeb 0 0 0
+				0xec 0 0 0
+				0xed 0 0 0
+				0xee 0 0 0
+				0xef 0 0 0>;
+		};
+
+		msi2: msi at 41a00 {
+			compatible = "fsl,mpic-msi";
+			reg = <0x41a00 0x200>;
+			msi-available-ranges = <0 0x100>;
+			interrupts = <
+				0xf0 0 0 0
+				0xf1 0 0 0
+				0xf2 0 0 0
+				0xf3 0 0 0
+				0xf4 0 0 0
+				0xf5 0 0 0
+				0xf6 0 0 0
+				0xf7 0 0 0>;
+		};
+
+		guts: global-utilities at e0000 {
+			compatible = "fsl,qoriq-device-config-1.0";
+			reg = <0xe0000 0xe00>;
+			fsl,has-rstcr;
+			#sleep-cells = <1>;
+			fsl,liodn-bits = <12>;
+		};
+
+		pins: global-utilities at e0e00 {
+			compatible = "fsl,qoriq-pin-control-1.0";
+			reg = <0xe0e00 0x200>;
+			#sleep-cells = <2>;
+		};
+
+		clockgen: global-utilities at e1000 {
+			compatible = "fsl,p3041-clockgen", "fsl,qoriq-clockgen-1.0";
+			reg = <0xe1000 0x1000>;
+			clock-frequency = <0>;
+		};
+
+		rcpm: global-utilities at e2000 {
+			compatible = "fsl,qoriq-rcpm-1.0";
+			reg = <0xe2000 0x1000>;
+			#sleep-cells = <1>;
+		};
+
+		sfp: sfp at e8000 {
+			compatible = "fsl,p3041-sfp", "fsl,qoriq-sfp-1.0";
+			reg	   = <0xe8000 0x1000>;
+		};
+
+		serdes: serdes at ea000 {
+			compatible = "fsl,p3041-serdes";
+			reg	   = <0xea000 0x1000>;
+		};
+
+		dma0: dma at 100300 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "fsl,p3041-dma", "fsl,eloplus-dma";
+			reg = <0x100300 0x4>;
+			ranges = <0x0 0x100100 0x200>;
+			cell-index = <0>;
+			dma-channel at 0 {
+				compatible = "fsl,p3041-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x0 0x80>;
+				cell-index = <0>;
+				interrupts = <28 2 0 0>;
+			};
+			dma-channel at 80 {
+				compatible = "fsl,p3041-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x80 0x80>;
+				cell-index = <1>;
+				interrupts = <29 2 0 0>;
+			};
+			dma-channel at 100 {
+				compatible = "fsl,p3041-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x100 0x80>;
+				cell-index = <2>;
+				interrupts = <30 2 0 0>;
+			};
+			dma-channel at 180 {
+				compatible = "fsl,p3041-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x180 0x80>;
+				cell-index = <3>;
+				interrupts = <31 2 0 0>;
+			};
+		};
+
+		dma1: dma at 101300 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "fsl,p3041-dma", "fsl,eloplus-dma";
+			reg = <0x101300 0x4>;
+			ranges = <0x0 0x101100 0x200>;
+			cell-index = <1>;
+			dma-channel at 0 {
+				compatible = "fsl,p3041-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x0 0x80>;
+				cell-index = <0>;
+				interrupts = <32 2 0 0>;
+			};
+			dma-channel at 80 {
+				compatible = "fsl,p3041-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x80 0x80>;
+				cell-index = <1>;
+				interrupts = <33 2 0 0>;
+			};
+			dma-channel at 100 {
+				compatible = "fsl,p3041-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x100 0x80>;
+				cell-index = <2>;
+				interrupts = <34 2 0 0>;
+			};
+			dma-channel at 180 {
+				compatible = "fsl,p3041-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x180 0x80>;
+				cell-index = <3>;
+				interrupts = <35 2 0 0>;
+			};
+		};
+
+		spi at 110000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,p3041-espi", "fsl,mpc8536-espi";
+			reg = <0x110000 0x1000>;
+			interrupts = <53 0x2 0 0>;
+			fsl,espi-num-chipselects = <4>;
+		};
+
+		sdhc: sdhc at 114000 {
+			compatible = "fsl,p3041-esdhc", "fsl,esdhc";
+			reg = <0x114000 0x1000>;
+			interrupts = <48 2 0 0>;
+			sdhci,auto-cmd12;
+			clock-frequency = <0>;
+		};
+
+		i2c at 118000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			cell-index = <0>;
+			compatible = "fsl-i2c";
+			reg = <0x118000 0x100>;
+			interrupts = <38 2 0 0>;
+			dfsrr;
+		};
+
+		i2c at 118100 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			cell-index = <1>;
+			compatible = "fsl-i2c";
+			reg = <0x118100 0x100>;
+			interrupts = <38 2 0 0>;
+			dfsrr;
+		};
+
+		i2c at 119000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			cell-index = <2>;
+			compatible = "fsl-i2c";
+			reg = <0x119000 0x100>;
+			interrupts = <39 2 0 0>;
+			dfsrr;
+		};
+
+		i2c at 119100 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			cell-index = <3>;
+			compatible = "fsl-i2c";
+			reg = <0x119100 0x100>;
+			interrupts = <39 2 0 0>;
+			dfsrr;
+		};
+
+		serial0: serial at 11c500 {
+			cell-index = <0>;
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <0x11c500 0x100>;
+			clock-frequency = <0>;
+			interrupts = <36 2 0 0>;
+		};
+
+		serial1: serial at 11c600 {
+			cell-index = <1>;
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <0x11c600 0x100>;
+			clock-frequency = <0>;
+			interrupts = <36 2 0 0>;
+		};
+
+		serial2: serial at 11d500 {
+			cell-index = <2>;
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <0x11d500 0x100>;
+			clock-frequency = <0>;
+			interrupts = <37 2 0 0>;
+		};
+
+		serial3: serial at 11d600 {
+			cell-index = <3>;
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <0x11d600 0x100>;
+			clock-frequency = <0>;
+			interrupts = <37 2 0 0>;
+		};
+
+		gpio0: gpio at 130000 {
+			compatible = "fsl,p3041-gpio", "fsl,qoriq-gpio";
+			reg = <0x130000 0x1000>;
+			interrupts = <55 2 0 0>;
+			#gpio-cells = <2>;
+			gpio-controller;
+		};
+
+		rman: rman at 1e0000 {
+			compatible = "fsl,rman";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x0 0x1e0000 0x20000>;
+			reg = <0x1e0000 0x20000>;
+			interrupts = <16 2 1 11>; /* err_irq */
+			fsl,qman-channels-id = <0x62 0x63>;
+
+			inbound-block at 0 {
+				compatible = "fsl,rman-inbound-block";
+				reg = <0x0 0x800>;
+			};
+			global-cfg at b00 {
+				compatible = "fsl,rman-global-cfg";
+				reg = <0xb00 0x500>;
+			};
+			inbound-block at 1000 {
+				compatible = "fsl,rman-inbound-block";
+				reg = <0x1000 0x800>;
+			};
+			inbound-block at 2000 {
+				compatible = "fsl,rman-inbound-block";
+				reg = <0x2000 0x800>;
+			};
+			inbound-block at 3000 {
+				compatible = "fsl,rman-inbound-block";
+				reg = <0x3000 0x800>;
+			};
+		};
+
+		usb0: usb at 210000 {
+			compatible = "fsl,p3041-usb2-mph",
+					"fsl,mpc85xx-usb2-mph", "fsl-usb2-mph";
+			reg = <0x210000 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			interrupts = <44 0x2 0 0>;
+			phy_type = "utmi";
+			port0;
+		};
+
+		usb1: usb at 211000 {
+			compatible = "fsl,p3041-usb2-dr",
+					"fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
+			reg = <0x211000 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			interrupts = <45 0x2 0 0>;
+			dr_mode = "host";
+			phy_type = "utmi";
+		};
+
+		sata at 220000 {
+			compatible = "fsl,p3041-sata", "fsl,pq-sata-v2";
+			reg = <0x220000 0x1000>;
+			interrupts = <68 0x2 0 0>;
+		};
+
+		sata at 221000 {
+			compatible = "fsl,p3041-sata", "fsl,pq-sata-v2";
+			reg = <0x221000 0x1000>;
+			interrupts = <69 0x2 0 0>;
+		};
+
+		crypto: crypto at 300000 {
+			compatible = "fsl,sec-v4.2", "fsl,sec-v4.0";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg		 = <0x300000 0x10000>;
+			ranges		 = <0 0x300000 0x10000>;
+			interrupts	 = <92 2 0 0>;
+
+			sec_jr0: jr at 1000 {
+				compatible = "fsl,sec-v4.2-job-ring",
+					     "fsl,sec-v4.0-job-ring";
+				reg = <0x1000 0x1000>;
+				interrupts = <88 2 0 0>;
+			};
+
+			sec_jr1: jr at 2000 {
+				compatible = "fsl,sec-v4.2-job-ring",
+					     "fsl,sec-v4.0-job-ring";
+				reg = <0x2000 0x1000>;
+				interrupts = <89 2 0 0>;
+			};
+
+			sec_jr2: jr at 3000 {
+				compatible = "fsl,sec-v4.2-job-ring",
+					     "fsl,sec-v4.0-job-ring";
+				reg = <0x3000 0x1000>;
+				interrupts = <90 2 0 0>;
+			};
+
+			sec_jr3: jr at 4000 {
+				compatible = "fsl,sec-v4.2-job-ring",
+					     "fsl,sec-v4.0-job-ring";
+				reg = <0x4000 0x1000>;
+				interrupts = <91 2 0 0>;
+			};
+
+			rtic at 6000 {
+				compatible = "fsl,sec-v4.2-rtic",
+					     "fsl,sec-v4.0-rtic";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				reg = <0x6000 0x100>;
+				ranges = <0x0 0x6100 0xe00>;
+
+				rtic_a: rtic-a at 0 {
+					compatible = "fsl,sec-v4.2-rtic-memory",
+						     "fsl,sec-v4.0-rtic-memory";
+					reg = <0x00 0x20 0x100 0x80>;
+				};
+
+				rtic_b: rtic-b at 20 {
+					compatible = "fsl,sec-v4.2-rtic-memory",
+						     "fsl,sec-v4.0-rtic-memory";
+					reg = <0x20 0x20 0x200 0x80>;
+				};
+
+				rtic_c: rtic-c at 40 {
+					compatible = "fsl,sec-v4.2-rtic-memory",
+						     "fsl,sec-v4.0-rtic-memory";
+					reg = <0x40 0x20 0x300 0x80>;
+				};
+
+				rtic_d: rtic-d at 60 {
+					compatible = "fsl,sec-v4.2-rtic-memory",
+						     "fsl,sec-v4.0-rtic-memory";
+					reg = <0x60 0x20 0x500 0x80>;
+				};
+			};
+		};
+
+		sec_mon: sec_mon at 314000 {
+			compatible = "fsl,sec-v4.2-mon", "fsl,sec-v4.0-mon";
+			reg = <0x314000 0x1000>;
+			interrupts = <93 2 0 0>;
+		};
+
+		pme: pme at 316000 {
+			compatible = "fsl,pme";
+			reg = <0x316000 0x10000>;
+			/* fsl,pme-pdsr = <0x0 0x23000000 0x0 0x01000000>; */
+			/* fsl,pme-sre = <0x0 0x24000000 0x0 0x00a00000>; */
+			interrupts = <16 2 1 5>;
+		};
+
+		qman: qman at 318000 {
+			compatible = "fsl,p3041-qman", "fsl,qman";
+			reg = <0x318000 0x1000>;
+			interrupts = <16 2 1 3>;
+			/* Commented out, use default allocation */
+			/* fsl,qman-fqd = <0x0 0x20000000 0x0 0x01000000>; */
+			/* fsl,qman-pfdr = <0x0 0x21000000 0x0 0x01000000>; */
+		};
+
+		bman: bman at 31a000 {
+			compatible = "fsl,p3041-bman", "fsl,bman";
+			reg = <0x31a000 0x1000>;
+			interrupts = <16 2 1 2>;
+			/* Same as fsl,qman-*, use default allocation */
+			/* fsl,bman-fbpr = <0x0 0x22000000 0x0 0x01000000>; */
+		};
+
+		fman0: fman at 400000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			cell-index = <0>;
+			compatible = "fsl,p3041-fman", "fsl,fman", "simple-bus";
+			ranges = <0 0x400000 0x100000>;
+			reg = <0x400000 0x100000>;
+			clock-frequency = <0>;
+			interrupts = <
+				96 2 0 0
+				16 2 1 1>;
+
+			cc at 0 {
+				compatible = "fsl,p3041-fman-cc", "fsl,fman-cc";
+			};
+
+			parser at c7000 {
+				compatible = "fsl,p3041-fman-parser", "fsl,fman-parser";
+				reg = <0xc7000 0x1000>;
+			};
+
+			keygen at c1000 {
+				compatible = "fsl,p3041-fman-keygen", "fsl,fman-keygen";
+				reg = <0xc1000 0x1000>;
+			};
+
+			policer at c0000 {
+				compatible = "fsl,p3041-fman-policer", "fsl,fman-policer";
+				reg = <0xc0000 0x1000>;
+			};
+
+			muram at 0 {
+				compatible = "fsl,p3041-fman-muram", "fsl,fman-muram";
+				reg = <0x0 0x28000>;
+			};
+
+			bmi at 80000 {
+				compatible = "fsl,p3041-fman-bmi", "fsl,fman-bmi";
+				reg = <0x80000 0x400>;
+			};
+
+			qmi at 80400 {
+				compatible = "fsl,p3041-fman-qmi", "fsl,fman-qmi";
+				reg = <0x80400 0x400>;
+			};
+
+			fman0_rx0: port at 88000 {
+				cell-index = <0>;
+				compatible = "fsl,p3041-fman-port-1g-rx", "fsl,fman-port-1g-rx";
+				reg = <0x88000 0x1000>;
+			};
+			fman0_rx1: port at 89000 {
+				cell-index = <1>;
+				compatible = "fsl,p3041-fman-port-1g-rx", "fsl,fman-port-1g-rx";
+				reg = <0x89000 0x1000>;
+			};
+			fman0_rx2: port at 8a000 {
+				cell-index = <2>;
+				compatible = "fsl,p3041-fman-port-1g-rx", "fsl,fman-port-1g-rx";
+				reg = <0x8a000 0x1000>;
+			};
+			fman0_rx3: port at 8b000 {
+				cell-index = <3>;
+				compatible = "fsl,p3041-fman-port-1g-rx", "fsl,fman-port-1g-rx";
+				reg = <0x8b000 0x1000>;
+			};
+			fman0_rx4: port at 8c000 {
+				cell-index = <4>;
+				compatible = "fsl,p3041-fman-port-1g-rx", "fsl,fman-port-1g-rx";
+				reg = <0x8c000 0x1000>;
+			};
+			fman0_rx5: port at 90000 {
+				cell-index = <0>;
+				compatible = "fsl,p3041-fman-port-10g-rx", "fsl,fman-port-10g-rx";
+				reg = <0x90000 0x1000>;
+			};
+
+			fman0_tx5: port at b0000 {
+				cell-index = <0>;
+				compatible = "fsl,p3041-fman-port-10g-tx", "fsl,fman-port-10g-tx";
+				reg = <0xb0000 0x1000>;
+				fsl,qman-channel-id = <0x40>;
+			};
+			fman0_tx0: port at a8000 {
+				cell-index = <0>;
+				compatible = "fsl,p3041-fman-port-1g-tx", "fsl,fman-port-1g-tx";
+				reg = <0xa8000 0x1000>;
+				fsl,qman-channel-id = <0x41>;
+			};
+			fman0_tx1: port at a9000 {
+				cell-index = <1>;
+				compatible = "fsl,p3041-fman-port-1g-tx", "fsl,fman-port-1g-tx";
+				reg = <0xa9000 0x1000>;
+				fsl,qman-channel-id = <0x42>;
+			};
+			fman0_tx2: port at aa000 {
+				cell-index = <2>;
+				compatible = "fsl,p3041-fman-port-1g-tx", "fsl,fman-port-1g-tx";
+				reg = <0xaa000 0x1000>;
+				fsl,qman-channel-id = <0x43>;
+			};
+			fman0_tx3: port at ab000 {
+				cell-index = <3>;
+				compatible = "fsl,p3041-fman-port-1g-tx", "fsl,fman-port-1g-tx";
+				reg = <0xab000 0x1000>;
+				fsl,qman-channel-id = <0x44>;
+			};
+			fman0_tx4: port at ac000 {
+				cell-index = <4>;
+				compatible = "fsl,p3041-fman-port-1g-tx", "fsl,fman-port-1g-tx";
+				reg = <0xac000 0x1000>;
+				fsl,qman-channel-id = <0x45>;
+			};
+
+			fman0_oh0: port at 81000 {
+				cell-index = <0>;
+				compatible = "fsl,p3041-fman-port-oh", "fsl,fman-port-oh";
+				reg = <0x81000 0x1000>;
+				fsl,qman-channel-id = <0x46>;
+			};
+			fman0_oh1: port at 82000 {
+				cell-index = <1>;
+				compatible = "fsl,p3041-fman-port-oh", "fsl,fman-port-oh";
+				reg = <0x82000 0x1000>;
+				fsl,qman-channel-id = <0x47>;
+			};
+			fman0_oh2: port at 83000 {
+				cell-index = <2>;
+				compatible = "fsl,p3041-fman-port-oh", "fsl,fman-port-oh";
+				reg = <0x83000 0x1000>;
+				fsl,qman-channel-id = <0x48>;
+			};
+			fman0_oh3: port at 84000 {
+				cell-index = <3>;
+				compatible = "fsl,p3041-fman-port-oh", "fsl,fman-port-oh";
+				reg = <0x84000 0x1000>;
+				fsl,qman-channel-id = <0x49>;
+			};
+			fman0_oh4: port at 85000 {
+				cell-index = <4>;
+				compatible = "fsl,p3041-fman-port-oh", "fsl,fman-port-oh";
+				reg = <0x85000 0x1000>;
+				fsl,qman-channel-id = <0x4a>;
+			};
+			fman0_oh5: port at 86000 {
+				cell-index = <5>;
+				compatible = "fsl,p3041-fman-port-oh", "fsl,fman-port-oh";
+				reg = <0x86000 0x1000>;
+				fsl,qman-channel-id = <0x4b>;
+			};
+			fman0_oh6: port at 87000 {
+				cell-index = <6>;
+				compatible = "fsl,p3041-fman-port-oh", "fsl,fman-port-oh";
+				reg = <0x87000 0x1000>;
+			};
+
+			enet0: ethernet at e0000 {
+				cell-index = <0>;
+				compatible = "fsl,p3041-fman-1g-mac", "fsl,fman-1g-mac";
+				reg = <0xe0000 0x1000>;
+				fsl,port-handles = <&fman0_rx0 &fman0_tx0>;
+				ptimer-handle = <&ptp_timer0>;
+			};
+
+			mdio0: mdio at e1120 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,fman-mdio";
+				reg = <0xe1120 0xee0>;
+				interrupts = <100 1 0 0>;
+			};
+
+			enet1: ethernet at e2000 {
+				cell-index = <1>;
+				compatible = "fsl,p3041-fman-1g-mac", "fsl,fman-1g-mac";
+				reg = <0xe2000 0x1000>;
+				fsl,port-handles = <&fman0_rx1 &fman0_tx1>;
+				ptimer-handle = <&ptp_timer0>;
+			};
+
+			mdio at e3120 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,fman-tbi";
+				reg = <0xe3120 0xee0>;
+				interrupts = <100 1 0 0>;
+			};
+
+			enet2: ethernet at e4000 {
+				cell-index = <2>;
+				compatible = "fsl,p3041-fman-1g-mac", "fsl,fman-1g-mac";
+				reg = <0xe4000 0x1000>;
+				fsl,port-handles = <&fman0_rx2 &fman0_tx2>;
+				ptimer-handle = <&ptp_timer0>;
+			};
+
+			mdio at e5120 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,fman-tbi";
+				reg = <0xe5120 0xee0>;
+				interrupts = <100 1 0 0>;
+			};
+
+			enet3: ethernet at e6000 {
+				cell-index = <3>;
+				compatible = "fsl,p3041-fman-1g-mac", "fsl,fman-1g-mac";
+				reg = <0xe6000 0x1000>;
+				fsl,port-handles = <&fman0_rx3 &fman0_tx3>;
+			};
+
+			mdio at e7120 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,fman-tbi";
+				reg = <0xe7120 0xee0>;
+				interrupts = <100 1 0 0>;
+			};
+
+			enet4: ethernet at e8000 {
+				cell-index = <4>;
+				compatible = "fsl,p3041-fman-1g-mac", "fsl,fman-1g-mac";
+				reg = <0xe8000 0x1000>;
+				fsl,port-handles = <&fman0_rx4 &fman0_tx4>;
+				ptimer-handle = <&ptp_timer0>;
+			};
+
+			mdio at e9120 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,fman-tbi";
+				reg = <0xe9120 0xee0>;
+				interrupts = <100 1 0 0>;
+			};
+
+			enet5: ethernet at f0000 {
+				cell-index = <0>;
+				compatible = "fsl,p3041-fman-10g-mac", "fsl,fman-10g-mac";
+				reg = <0xf0000 0x1000>;
+				fsl,port-handles = <&fman0_rx5 &fman0_tx5>;
+			};
+
+			mdio at f1000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,fman-xmdio";
+				reg = <0xf1000 0x1000>;
+				interrupts = <100 1 0 0>;
+			};
+
+			ptp_timer0: rtc at fe000 {
+				compatible = "fsl,fman-rtc";
+				reg = <0xfe000 0x1000>;
+			};
+		};
+	};
+
+	rapidio at ffe0c0000 {
+		compatible = "fsl,srio";
+		interrupts = <16 2 1 11>;
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		port1 {
+			#address-cells = <2>;
+			#size-cells = <2>;
+			cell-index = <1>;
+		};
+
+		port2 {
+			#address-cells = <2>;
+			#size-cells = <2>;
+			cell-index = <2>;
+		};
+	};
+
+	localbus at ffe124000 {
+		compatible = "fsl,p3041-rev1.0-elbc", "simple-bus", "fsl,elbc";
+		interrupts = <
+			25 2 0 0
+			16 2 1 19
+			>;
+		#address-cells = <2>;
+		#size-cells = <1>;
+	};
+
+	pci0: pcie at ffe200000 {
+		compatible = "fsl,p3041-pcie", "fsl,qoriq-pcie-v2.2";
+		device_type = "pci";
+		status = "okay";
+		#size-cells = <2>;
+		#address-cells = <3>;
+		bus-range = <0x0 0xff>;
+		clock-frequency = <0x1fca055>;
+		fsl,msi = <&msi0>;
+		interrupts = <16 2 1 15>;
+
+		pcie at 0 {
+			reg = <0 0 0 0 0>;
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			device_type = "pci";
+			interrupts = <16 2 1 15>;
+			interrupt-map-mask = <0xf800 0 0 7>;
+			interrupt-map = <
+				/* IDSEL 0x0 */
+				0000 0 0 1 &mpic 40 1 0 0
+				0000 0 0 2 &mpic 1 1 0 0
+				0000 0 0 3 &mpic 2 1 0 0
+				0000 0 0 4 &mpic 3 1 0 0
+				>;
+		};
+	};
+
+	pci1: pcie at ffe201000 {
+		compatible = "fsl,p3041-pcie", "fsl,qoriq-pcie-v2.2";
+		device_type = "pci";
+		status = "disabled";
+		#size-cells = <2>;
+		#address-cells = <3>;
+		bus-range = <0 0xff>;
+		clock-frequency = <0x1fca055>;
+		fsl,msi = <&msi1>;
+		interrupts = <16 2 1 14>;
+		pcie at 0 {
+			reg = <0 0 0 0 0>;
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			device_type = "pci";
+			interrupts = <16 2 1 14>;
+			interrupt-map-mask = <0xf800 0 0 7>;
+			interrupt-map = <
+				/* IDSEL 0x0 */
+				0000 0 0 1 &mpic 41 1 0 0
+				0000 0 0 2 &mpic 5 1 0 0
+				0000 0 0 3 &mpic 6 1 0 0
+				0000 0 0 4 &mpic 7 1 0 0
+				>;
+		};
+	};
+
+	pci2: pcie at ffe202000 {
+		compatible = "fsl,p3041-pcie", "fsl,qoriq-pcie-v2.2";
+		device_type = "pci";
+		status = "okay";
+		#size-cells = <2>;
+		#address-cells = <3>;
+		bus-range = <0x0 0xff>;
+		clock-frequency = <0x1fca055>;
+		fsl,msi = <&msi2>;
+		interrupts = <16 2 1 13>;
+		pcie at 0 {
+			reg = <0 0 0 0 0>;
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			device_type = "pci";
+			interrupts = <16 2 1 13>;
+			interrupt-map-mask = <0xf800 0 0 7>;
+			interrupt-map = <
+				/* IDSEL 0x0 */
+				0000 0 0 1 &mpic 42 1 0 0
+				0000 0 0 2 &mpic 9 1 0 0
+				0000 0 0 3 &mpic 10 1 0 0
+				0000 0 0 4 &mpic 11 1 0 0
+				>;
+		};
+	};
+
+	pci3: pcie at ffe203000 {
+		compatible = "fsl,p3041-pcie", "fsl,qoriq-pcie-v2.2";
+		device_type = "pci";
+		status = "disabled";
+		#size-cells = <2>;
+		#address-cells = <3>;
+		bus-range = <0x0 0xff>;
+		clock-frequency = <0x1fca055>;
+		fsl,msi = <&msi2>;
+		interrupts = <16 2 1 12>;
+		pcie at 0 {
+			reg = <0 0 0 0 0>;
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			device_type = "pci";
+			interrupts = <16 2 1 12>;
+			interrupt-map-mask = <0xf800 0 0 7>;
+			interrupt-map = <
+				/* IDSEL 0x0 */
+				0000 0 0 1 &mpic 43 1 0 0
+				0000 0 0 2 &mpic 0 1 0 0
+				0000 0 0 3 &mpic 4 1 0 0
+				0000 0 0 4 &mpic 8 1 0 0
+				>;
+		};
+	};
+};
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/fdt/dts/p5020ds.dts
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/boot/fdt/dts/p5020ds.dts	Wed Jul 25 16:45:04 2012 +0300
@@ -0,0 +1,583 @@
+/*
+ * P5020DS Device Tree Source
+ *
+ * Copyright 2010-2011 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/* $FreeBSD: head/sys/boot/fdt/dts/p5020ds.dts 236024 2012-05-25 20:43:38Z raj $ */
+
+/include/ "p5020si.dtsi"
+
+/ {
+	model = "fsl,P5020DS";
+	compatible = "fsl,P5020DS";
+	#address-cells = <2>;
+	#size-cells = <2>;
+	interrupt-parent = <&mpic>;
+
+	aliases {
+		phy_rgmii_0 = &phy_rgmii_0;
+		phy_rgmii_1 = &phy_rgmii_1;
+		phy_sgmii_1c = &phy_sgmii_1c;
+		phy_sgmii_1d = &phy_sgmii_1d;
+		phy_sgmii_1e = &phy_sgmii_1e;
+		phy_sgmii_1f = &phy_sgmii_1f;
+		phy_xgmii_1 = &phy_xgmii_1;
+		phy_xgmii_2 = &phy_xgmii_2;
+		emi1_rgmii = &hydra_mdio_rgmii;
+		emi1_sgmii = &hydra_mdio_sgmii;
+		emi2_xgmii = &hydra_mdio_xgmii;
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x00000000 0x00000000 0x80000000>;
+	};
+
+	dcsr: dcsr at f00000000 {
+		ranges = <0x00000000 0xf 0x00000000 0x01008000>;
+	};
+
+	bman-portals at ff4000000 {
+		bman-portal at 0 {
+			cpu-handle = <&cpu0>;
+		};
+		bman-portal at 4000 {
+			cpu-handle = <&cpu1>;
+		};
+		bman-portal at 8000 {
+		};
+		bman-portal at c000 {
+		};
+		bman-portal at 10000 {
+		};
+		bman-portal at 14000 {
+		};
+		bman-portal at 18000 {
+		};
+		bman-portal at 1c000 {
+		};
+		bman-portal at 20000 {
+		};
+		bman-portal at 24000 {
+		};
+
+		buffer-pool at 0 {
+			compatible = "fsl,p5020-bpool", "fsl,bpool";
+			fsl,bpid = <0>;
+			fsl,bpool-cfg = <0 0x100 0 1 0 0x100>;
+		};
+	};
+
+	qman-portals at ff4200000 {
+		qportal0: qman-portal at 0 {
+			cpu-handle = <&cpu0>;
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal1: qman-portal at 4000 {
+			cpu-handle = <&cpu1>;
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal2: qman-portal at 8000 {
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal3: qman-portal at c000 {
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal4: qman-portal at 10000 {
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal5: qman-portal at 14000 {
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal6: qman-portal at 18000 {
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal7: qman-portal at 1c000 {
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal8: qman-portal at 20000 {
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+
+		qportal9: qman-portal at 24000 {
+			fsl,qman-pool-channels = <&qpool1 &qpool2 &qpool3
+						  &qpool4 &qpool5 &qpool6
+						  &qpool7 &qpool8 &qpool9
+						  &qpool10 &qpool11 &qpool12
+						  &qpool13 &qpool14 &qpool15>;
+		};
+	};
+
+	soc: soc at ffe000000 {
+		spi at 110000 {
+			flash at 0 {
+				#address-cells = <1>;
+				#size-cells = <1>;
+				compatible = "spansion,s25sl12801";
+				reg = <0>;
+				spi-max-frequency = <40000000>; /* input clock */
+				partition at u-boot {
+					label = "u-boot";
+					reg = <0x00000000 0x00100000>;
+					read-only;
+				};
+				partition at kernel {
+					label = "kernel";
+					reg = <0x00100000 0x00500000>;
+					read-only;
+				};
+				partition at dtb {
+					label = "dtb";
+					reg = <0x00600000 0x00100000>;
+					read-only;
+				};
+				partition at fs {
+					label = "file system";
+					reg = <0x00700000 0x00900000>;
+				};
+			};
+		};
+
+		i2c at 118100 {
+			eeprom at 51 {
+				compatible = "at24,24c256";
+				reg = <0x51>;
+			};
+			eeprom at 52 {
+				compatible = "at24,24c256";
+				reg = <0x52>;
+			};
+		};
+
+		i2c at 119100 {
+			rtc at 68 {
+				compatible = "dallas,ds3232";
+				reg = <0x68>;
+				interrupts = <0x1 0x1 0 0>;
+			};
+		};
+
+		pme: pme at 316000 {
+			/* Commented out, use default allocation */
+			/* fsl,pme-pdsr = <0x0 0x23000000 0x0 0x01000000>; */
+			/* fsl,pme-sre = <0x0 0x24000000 0x0 0x00a00000>; */
+		};
+
+		qman: qman at 318000 {
+			/* Commented out, use default allocation */
+			/* fsl,qman-fqd = <0x0 0x20000000 0x0 0x01000000>; */
+			/* fsl,qman-pfdr = <0x0 0x21000000 0x0 0x01000000>; */
+		};
+
+		bman: bman at 31a000 {
+			/* Same as fsl,qman-*, use default allocation */
+			/* fsl,bman-fbpr = <0x0 0x22000000 0x0 0x01000000>; */
+		};
+
+		fman0: fman at 400000 {
+			enet0: ethernet at e0000 {
+				tbi-handle = <&tbi0>;
+				phy-handle = <&phy_rgmii_0>;
+				phy-connection-type = "rgmii";
+			};
+
+			mdio0: mdio at e1120 {
+				tbi0: tbi-phy at 8 {
+					reg = <0x8>;
+					device_type = "tbi-phy";
+				};
+
+				/*
+				 * Virtual MDIO for the two on-board RGMII
+				 * ports.  The fsl,hydra-mdio-muxval property
+				 * is already correct.
+				 */
+				hydra_mdio_rgmii: hydra-mdio-rgmii {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					compatible = "fsl,hydra-mdio";
+					fsl,mdio-handle = <&mdio0>;
+					fsl,hydra-mdio-muxval = <0x00>;
+					status = "disabled";
+
+					phy_rgmii_0: ethernet-phy at 0 {
+						reg = <0x0>;
+					};
+					phy_rgmii_1: ethernet-phy at 1 {
+						reg = <0x1>;
+					};
+				};
+
+				/*
+				 * Virtual MDIO for the four-port SGMII card.
+				 * The fsl,hydra-mdio-muxval property will be
+				 * fixed-up by U-Boot based on the slot that
+				 * the SGMII card is in.
+				 *
+				 * Note: we do not support DTSEC5 connected to
+				 * SGMII, so this is the only SGMII node.
+				 */
+				hydra_mdio_sgmii: hydra-mdio-sgmii {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					compatible = "fsl,hydra-mdio";
+					fsl,mdio-handle = <&mdio0>;
+					fsl,hydra-mdio-muxval = <0x00>;
+					status = "disabled";
+
+					phy_sgmii_1c: ethernet-phy at 1c {
+						reg = <0x1c>;
+					};
+					phy_sgmii_1d: ethernet-phy at 1d {
+						reg = <0x1d>;
+					};
+					phy_sgmii_1e: ethernet-phy at 1e {
+						reg = <0x1e>;
+					};
+					phy_sgmii_1f: ethernet-phy at 1f {
+						reg = <0x1f>;
+					};
+				};
+			};
+
+			enet1: ethernet at e2000 {
+				tbi-handle = <&tbi1>;
+				phy-handle = <&phy_sgmii_1d>;
+				phy-connection-type = "sgmii";
+			};
+
+			mdio at e3120 {
+				tbi1: tbi-phy at 8 {
+					reg = <8>;
+					device_type = "tbi-phy";
+				};
+			};
+
+			enet2: ethernet at e4000 {
+				tbi-handle = <&tbi2>;
+				phy-handle = <&phy_sgmii_1e>;
+				phy-connection-type = "sgmii";
+			};
+
+			mdio at e5120 {
+				tbi2: tbi-phy at 8 {
+					reg = <8>;
+					device_type = "tbi-phy";
+				};
+			};
+
+			enet3: ethernet at e6000 {
+				tbi-handle = <&tbi3>;
+				phy-handle = <&phy_sgmii_1f>;
+				phy-connection-type = "sgmii";
+			};
+
+			mdio at e7120 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,fman-tbi";
+				reg = <0xe7120 0xee0>;
+				interrupts = <100 1 0 0>;
+
+				tbi3: tbi-phy at 8 {
+					reg = <8>;
+					device_type = "tbi-phy";
+				};
+			};
+
+			enet4: ethernet at e8000 {
+				tbi-handle = <&tbi4>;
+				phy-handle = <&phy_rgmii_1>;
+				phy-connection-type = "rgmii";
+			};
+
+			mdio at e9120 {
+				tbi4: tbi-phy at 8 {
+					reg = <8>;
+					device_type = "tbi-phy";
+				};
+			};
+
+			enet5: ethernet at f0000 {
+				/*
+				 * phy-handle will be updated by U-Boot to
+				 * reflect the actual slot the XAUI card is in.
+				 */
+				phy-handle = <&phy_xgmii_1>;
+				phy-connection-type = "xgmii";
+			};
+
+			/*
+			 * We only support one XAUI card, so the MDIO muxing
+			 * is set by U-Boot, and Linux never touches it.
+			 * Therefore, we don't need a virtual MDIO node.
+			 * However, the phy address depends on the slot, so
+			 * only one of the ethernet-phy nodes below will be
+			 * used.
+			 */
+			hydra_mdio_xgmii: mdio at f1000 {
+				status = "disabled";
+
+				/* XAUI card in slot 1 */
+				phy_xgmii_1: ethernet-phy at 4 {
+					reg = <0x4>;
+				};
+
+				/* XAUI card in slot 2 */
+				phy_xgmii_2: ethernet-phy at 0 {
+					reg = <0x0>;
+				};
+			};
+		};
+	};
+
+	rapidio at ffe0c0000 {
+		reg = <0xf 0xfe0c0000 0 0x11000>;
+
+		port1 {
+			ranges = <0 0 0xc 0x20000000 0 0x10000000>;
+		};
+		port2 {
+			ranges = <0 0 0xc 0x30000000 0 0x10000000>;
+		};
+	};
+
+	localbus at ffe124000 {
+		reg = <0xf 0xfe124000 0 0x1000>;
+		ranges = <0 0 0xf 0xb8000000 0x04000000>;
+
+		flash at 0,0 {
+			compatible = "cfi-flash";
+			/*
+                         * Map 64Mb of 128MB NOR flash memory. Since highest
+                         * line of address of NOR flash memory are set by
+                         * FPGA, memory are divided into two pages equal to
+                         * 64MB. One of the pages can be accessed at once.
+                         */
+			reg = <0 0 0x04000000>;
+			bank-width = <2>;
+			device-width = <2>;
+		};
+
+		nand at 2,0 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "fsl,elbc-fcm-nand";
+			reg = <0x2 0x0 0x40000>;
+
+			partition at 0 {
+				label = "NAND U-Boot Image";
+				reg = <0x0 0x02000000>;
+				read-only;
+			};
+
+			partition at 2000000 {
+				label = "NAND Root File System";
+				reg = <0x02000000 0x10000000>;
+			};
+
+			partition at 12000000 {
+				label = "NAND Compressed RFS Image";
+				reg = <0x12000000 0x08000000>;
+			};
+
+			partition at 1a000000 {
+				label = "NAND Linux Kernel Image";
+				reg = <0x1a000000 0x04000000>;
+			};
+
+			partition at 1e000000 {
+				label = "NAND DTB Image";
+				reg = <0x1e000000 0x01000000>;
+			};
+
+			partition at 1f000000 {
+				label = "NAND Writable User area";
+				reg = <0x1f000000 0x21000000>;
+			};
+		};
+
+		board-control at 3,0 {
+			compatible = "fsl,p5020ds-fpga", "fsl,fpga-ngpixis";
+			reg = <3 0 0x30>;
+		};
+	};
+
+	pci0: pcie at ffe200000 {
+		reg = <0xf 0xfe200000 0 0x1000>;
+		ranges = <0x02000000 0 0x80000000 0x0 0x80000000 0x0 0x10000000
+			  0x01000000 0 0x00000000 0x0 0xff000000 0x0 0x00010000>;
+		pcie at 0 {
+			ranges = <0x02000000 0 0x80000000
+				  0x02000000 0 0x80000000
+				  0 0x10000000
+
+				  0x01000000 0 0x00000000
+				  0x01000000 0 0xff000000
+				  0 0x00010000>;
+		};
+	};
+
+	pci1: pcie at ffe201000 {
+		reg = <0xf 0xfe201000 0 0x1000>;
+		ranges = <0x02000000 0x0 0x90000000 0x0 0x90000000 0x0 0x10000000
+			  0x01000000 0x0 0x00000000 0x0 0xff010000 0x0 0x00010000>;
+		pcie at 0 {
+			ranges = <0x02000000 0 0x90000000
+				  0x02000000 0 0x90000000
+				  0 0x10000000
+
+				  0x01000000 0 0x00000000
+				  0x01000000 0 0xff010000
+				  0 0x00010000>;
+		};
+	};
+
+	pci2: pcie at ffe202000 {
+		reg = <0xf 0xfe202000 0 0x1000>;
+		ranges = <0x02000000 0 0xa0000000 0x0 0xa0000000 0 0x10000000
+			  0x01000000 0 0x00000000 0x0 0xff020000 0 0x00010000>;
+		pcie at 0 {
+			ranges = <0x02000000 0 0xa0000000
+				  0x02000000 0 0xa0000000
+				  0 0x10000000
+
+				  0x01000000 0 0x00000000
+				  0x01000000 0 0xff020000
+				  0 0x00010000>;
+		};
+	};
+
+	pci3: pcie at ffe203000 {
+		reg = <0xf 0xfe203000 0 0x1000>;
+		ranges = <0x02000000 0 0xb0000000 0x0 0xb0000000 0 0x08000000
+			  0x01000000 0 0x00000000 0x0 0xff030000 0 0x00010000>;
+		pcie at 0 {
+			ranges = <0x02000000 0 0xb0000000
+				  0x02000000 0 0xb0000000
+				  0 0x08000000
+
+				  0x01000000 0 0x00000000
+				  0x01000000 0 0xff030000
+				  0 0x00010000>;
+		};
+	};
+
+	fsl,dpaa {
+		compatible = "fsl,p5020-dpaa", "fsl,dpaa";
+
+		ethernet at 0 {
+			compatible = "fsl,p5020-dpa-ethernet", "fsl,dpa-ethernet";
+			fsl,qman-channel = <&qpool1>;
+			fsl,fman-mac = <&enet0>;
+			status = "okay";
+		};
+		ethernet at 1 {
+			compatible = "fsl,p5020-dpa-ethernet", "fsl,dpa-ethernet";
+			fsl,qman-channel = <&qpool1>;
+			fsl,fman-mac = <&enet1>;
+			status = "disabled";
+		};
+		ethernet at 2 {
+			compatible = "fsl,p5020-dpa-ethernet", "fsl,dpa-ethernet";
+			fsl,qman-channel = <&qpool1>;
+			fsl,fman-mac = <&enet2>;
+			status = "disabled";
+		};
+		ethernet at 3 {
+			compatible = "fsl,p5020-dpa-ethernet", "fsl,dpa-ethernet";
+			fsl,qman-channel = <&qpool1>;
+			fsl,fman-mac = <&enet3>;
+			status = "disabled";
+		};
+		ethernet at 4 {
+			compatible = "fsl,p5020-dpa-ethernet", "fsl,dpa-ethernet";
+			fsl,qman-channel = <&qpool1>;
+			fsl,fman-mac = <&enet4>;
+			status = "okay";
+		};
+		ethernet at 5 {
+			compatible = "fsl,p5020-dpa-ethernet", "fsl,dpa-ethernet";
+			fsl,qman-channel = <&qpool1>;
+			fsl,fman-mac = <&enet5>;
+			status = "disabled";
+		};
+	};
+
+	chosen {
+		stdin = "serial0";
+		stdout = "serial0";
+	};
+};
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/fdt/dts/p5020si.dtsi
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/boot/fdt/dts/p5020si.dtsi	Wed Jul 25 16:45:04 2012 +0300
@@ -0,0 +1,1389 @@
+/*
+ * P5020 Silicon Device Tree Source
+ *
+ * Copyright 2010-2011 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/* $FreeBSD: head/sys/boot/fdt/dts/p5020si.dtsi 236024 2012-05-25 20:43:38Z raj $ */
+
+/dts-v1/;
+
+/ {
+	compatible = "fsl,P5020";
+	#address-cells = <2>;
+	#size-cells = <2>;
+	interrupt-parent = <&mpic>;
+
+	aliases {
+		ccsr = &soc;
+		dcsr = &dcsr;
+
+		ethernet0 = &enet0;
+		ethernet1 = &enet1;
+		ethernet2 = &enet2;
+		ethernet3 = &enet3;
+		ethernet4 = &enet4;
+		ethernet5 = &enet5;
+		serial0 = &serial0;
+		serial1 = &serial1;
+		serial2 = &serial2;
+		serial3 = &serial3;
+		pci0 = &pci0;
+		pci1 = &pci1;
+		pci2 = &pci2;
+		pci3 = &pci3;
+		usb0 = &usb0;
+		usb1 = &usb1;
+		dma0 = &dma0;
+		dma1 = &dma1;
+		bman = &bman;
+		qman = &qman;
+		pme = &pme;
+		rman = &rman;
+		sdhc = &sdhc;
+		msi0 = &msi0;
+		msi1 = &msi1;
+		msi2 = &msi2;
+
+		crypto = &crypto;
+		sec_jr0 = &sec_jr0;
+		sec_jr1 = &sec_jr1;
+		sec_jr2 = &sec_jr2;
+		sec_jr3 = &sec_jr3;
+		rtic_a = &rtic_a;
+		rtic_b = &rtic_b;
+		rtic_c = &rtic_c;
+		rtic_d = &rtic_d;
+		sec_mon = &sec_mon;
+
+		raideng = &raideng;
+		raideng_jr0 = &raideng_jr0;
+		raideng_jr1 = &raideng_jr1;
+		raideng_jr2 = &raideng_jr2;
+		raideng_jr3 = &raideng_jr3;
+
+		fman0 = &fman0;
+		fman0_oh0 = &fman0_oh0;
+		fman0_oh1 = &fman0_oh1;
+		fman0_oh2 = &fman0_oh2;
+		fman0_oh3 = &fman0_oh3;
+		fman0_oh4 = &fman0_oh4;
+		fman0_oh5 = &fman0_oh5;
+		fman0_oh6 = &fman0_oh6;
+		fman0_rx0 = &fman0_rx0;
+		fman0_rx1 = &fman0_rx1;
+		fman0_rx2 = &fman0_rx2;
+		fman0_rx3 = &fman0_rx3;
+		fman0_rx4 = &fman0_rx4;
+		fman0_rx5 = &fman0_rx5;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu0: PowerPC,e5500 at 0 {
+			device_type = "cpu";
+			reg = <0>;
+			bus-frequency = <799999998>;
+			next-level-cache = <&L2_0>;
+			L2_0: l2-cache {
+				next-level-cache = <&cpc>;
+			};
+		};
+		cpu1: PowerPC,e5500 at 1 {
+			device_type = "cpu";
+			reg = <1>;
+			next-level-cache = <&L2_1>;
+			L2_1: l2-cache {
+				next-level-cache = <&cpc>;
+			};
+		};
+	};
+
+	dcsr: dcsr at f00000000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "fsl,dcsr", "simple-bus";
+
+		dcsr-epu at 0 {
+			compatible = "fsl,dcsr-epu";
+			interrupts = <52 2 0 0
+				      84 2 0 0
+				      85 2 0 0>;
+			interrupt-parent = <&mpic>;
+			reg = <0x0 0x1000>;
+		};
+		dcsr-npc {
+			compatible = "fsl,dcsr-npc";
+			reg = <0x1000 0x1000 0x1000000 0x8000>;
+		};
+		dcsr-nxc at 2000 {
+			compatible = "fsl,dcsr-nxc";
+			reg = <0x2000 0x1000>;
+		};
+		dcsr-corenet {
+			compatible = "fsl,dcsr-corenet";
+			reg = <0x8000 0x1000 0xB0000 0x1000>;
+		};
+		dcsr-dpaa at 9000 {
+			compatible = "fsl,p5020-dcsr-dpaa", "fsl,dcsr-dpaa";
+			reg = <0x9000 0x1000>;
+		};
+		dcsr-ocn at 11000 {
+			compatible = "fsl,p5020-dcsr-ocn", "fsl,dcsr-ocn";
+			reg = <0x11000 0x1000>;
+		};
+		dcsr-ddr at 12000 {
+			compatible = "fsl,dcsr-ddr";
+			dev-handle = <&ddr1>;
+			reg = <0x12000 0x1000>;
+		};
+		dcsr-ddr at 13000 {
+			compatible = "fsl,dcsr-ddr";
+			dev-handle = <&ddr2>;
+			reg = <0x13000 0x1000>;
+		};
+		dcsr-nal at 18000 {
+			compatible = "fsl,p5020-dcsr-nal", "fsl,dcsr-nal";
+			reg = <0x18000 0x1000>;
+		};
+		dcsr-rcpm at 22000 {
+			compatible = "fsl,p5020-dcsr-rcpm", "fsl,dcsr-rcpm";
+			reg = <0x22000 0x1000>;
+		};
+		dcsr-cpu-sb-proxy at 40000 {
+			compatible = "fsl,dcsr-e5500-sb-proxy", "fsl,dcsr-cpu-sb-proxy";
+			cpu-handle = <&cpu0>;
+			reg = <0x40000 0x1000>;
+		};
+		dcsr-cpu-sb-proxy at 41000 {
+			compatible = "fsl,dcsr-e5500-sb-proxy", "fsl,dcsr-cpu-sb-proxy";
+			cpu-handle = <&cpu1>;
+			reg = <0x41000 0x1000>;
+		};
+	};
+
+	bman-portals at ff4000000 {
+		#address-cells = <0x1>;
+		#size-cells = <0x1>;
+		compatible = "bman-portals";
+		ranges = <0x0 0xf 0xfde00000 0x200000>;
+		bman-portal at 0 {
+			cell-index = <0x0>;
+			compatible = "fsl,p5020-bman-portal", "fsl,bman-portal";
+			reg = <0x0 0x4000 0x100000 0x1000>;
+			interrupts = <105 2 0 0>;
+		};
+		bman-portal at 4000 {
+			cell-index = <0x1>;
+			compatible = "fsl,p5020-bman-portal", "fsl,bman-portal";
+			reg = <0x4000 0x4000 0x101000 0x1000>;
+			interrupts = <107 2 0 0>;
+		};
+		bman-portal at 8000 {
+			cell-index = <2>;
+			compatible = "fsl,p5020-bman-portal", "fsl,bman-portal";
+			reg = <0x8000 0x4000 0x102000 0x1000>;
+			interrupts = <109 2 0 0>;
+		};
+		bman-portal at c000 {
+			cell-index = <0x3>;
+			compatible = "fsl,p5020-bman-portal", "fsl,bman-portal";
+			reg = <0xc000 0x4000 0x103000 0x1000>;
+			interrupts = <111 2 0 0>;
+		};
+		bman-portal at 10000 {
+			cell-index = <0x4>;
+			compatible = "fsl,p5020-bman-portal", "fsl,bman-portal";
+			reg = <0x10000 0x4000 0x104000 0x1000>;
+			interrupts = <113 2 0 0>;
+		};
+		bman-portal at 14000 {
+			cell-index = <0x5>;
+			compatible = "fsl,p5020-bman-portal", "fsl,bman-portal";
+			reg = <0x14000 0x4000 0x105000 0x1000>;
+			interrupts = <115 2 0 0>;
+		};
+		bman-portal at 18000 {
+			cell-index = <0x6>;
+			compatible = "fsl,p5020-bman-portal", "fsl,bman-portal";
+			reg = <0x18000 0x4000 0x106000 0x1000>;
+			interrupts = <117 2 0 0>;
+		};
+		bman-portal at 1c000 {
+			cell-index = <0x7>;
+			compatible = "fsl,p5020-bman-portal", "fsl,bman-portal";
+			reg = <0x1c000 0x4000 0x107000 0x1000>;
+			interrupts = <119 2 0 0>;
+		};
+		bman-portal at 20000 {
+			cell-index = <0x8>;
+			compatible = "fsl,p5020-bman-portal", "fsl,bman-portal";
+			reg = <0x20000 0x4000 0x108000 0x1000>;
+			interrupts = <121 2 0 0>;
+		};
+		bman-portal at 24000 {
+			cell-index = <0x9>;
+			compatible = "fsl,p5020-bman-portal", "fsl,bman-portal";
+			reg = <0x24000 0x4000 0x109000 0x1000>;
+			interrupts = <123 2 0 0>;
+		};
+
+		buffer-pool at 0 {
+			compatible = "fsl,p5020-bpool", "fsl,bpool";
+			fsl,bpid = <0>;
+			fsl,bpool-cfg = <0 0x100 0 1 0 0x100>;
+		};
+	};
+
+	qman-portals at ff4200000 {
+		#address-cells = <0x1>;
+		#size-cells = <0x1>;
+		compatible = "qman-portals";
+		ranges = <0x0 0xf 0xfdc00000 0x200000>;
+		qportal0: qman-portal at 0 {
+			cell-index = <0x0>;
+			compatible = "fsl,p5020-qman-portal", "fsl,qman-portal";
+			reg = <0x0 0x4000 0x100000 0x1000>;
+			interrupts = <104 0x2 0 0>;
+			fsl,qman-channel-id = <0x0>;
+		};
+
+		qportal1: qman-portal at 4000 {
+			cell-index = <0x1>;
+			compatible = "fsl,p5020-qman-portal", "fsl,qman-portal";
+			reg = <0x4000 0x4000 0x101000 0x1000>;
+			interrupts = <106 0x2 0 0>;
+			fsl,qman-channel-id = <0x1>;
+		};
+
+		qportal2: qman-portal at 8000 {
+			cell-index = <0x2>;
+			compatible = "fsl,p5020-qman-portal", "fsl,qman-portal";
+			reg = <0x8000 0x4000 0x102000 0x1000>;
+			interrupts = <108 0x2 0 0>;
+			fsl,qman-channel-id = <0x2>;
+		};
+
+		qportal3: qman-portal at c000 {
+			cell-index = <0x3>;
+			compatible = "fsl,p5020-qman-portal", "fsl,qman-portal";
+			reg = <0xc000 0x4000 0x103000 0x1000>;
+			interrupts = <110 0x2 0 0>;
+			fsl,qman-channel-id = <0x3>;
+		};
+
+		qportal4: qman-portal at 10000 {
+			cell-index = <0x4>;
+			compatible = "fsl,p5020-qman-portal", "fsl,qman-portal";
+			reg = <0x10000 0x4000 0x104000 0x1000>;
+			interrupts = <112 0x2 0 0>;
+			fsl,qman-channel-id = <0x4>;
+		};
+
+		qportal5: qman-portal at 14000 {
+			cell-index = <0x5>;
+			compatible = "fsl,p5020-qman-portal", "fsl,qman-portal";
+			reg = <0x14000 0x4000 0x105000 0x1000>;
+			interrupts = <114 0x2 0 0>;
+			fsl,qman-channel-id = <0x5>;
+		};
+
+		qportal6: qman-portal at 18000 {
+			cell-index = <0x6>;
+			compatible = "fsl,p5020-qman-portal", "fsl,qman-portal";
+			reg = <0x18000 0x4000 0x106000 0x1000>;
+			interrupts = <116 0x2 0 0>;
+			fsl,qman-channel-id = <0x6>;
+		};
+
+		qportal7: qman-portal at 1c000 {
+			cell-index = <0x7>;
+			compatible = "fsl,p5020-qman-portal", "fsl,qman-portal";
+			reg = <0x1c000 0x4000 0x107000 0x1000>;
+			interrupts = <118 0x2 0 0>;
+			fsl,qman-channel-id = <0x7>;
+		};
+
+		qportal8: qman-portal at 20000 {
+			cell-index = <0x8>;
+			compatible = "fsl,p5020-qman-portal", "fsl,qman-portal";
+			reg = <0x20000 0x4000 0x108000 0x1000>;
+			interrupts = <120 0x2 0 0>;
+			fsl,qman-channel-id = <0x8>;
+		};
+
+		qportal9: qman-portal at 24000 {
+			cell-index = <0x9>;
+			compatible = "fsl,p5020-qman-portal", "fsl,qman-portal";
+			reg = <0x24000 0x4000 0x109000 0x1000>;
+			interrupts = <122 0x2 0 0>;
+			fsl,qman-channel-id = <0x9>;
+		};
+
+		qpool1: qman-pool at 1 {
+			cell-index = <1>;
+			compatible = "fsl,p5020-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x21>;
+		};
+
+		qpool2: qman-pool at 2 {
+			cell-index = <2>;
+			compatible = "fsl,p5020-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x22>;
+		};
+
+		qpool3: qman-pool at 3 {
+			cell-index = <3>;
+			compatible = "fsl,p5020-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x23>;
+		};
+
+		qpool4: qman-pool at 4 {
+			cell-index = <4>;
+			compatible = "fsl,p5020-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x24>;
+		};
+
+		qpool5: qman-pool at 5 {
+			cell-index = <5>;
+			compatible = "fsl,p5020-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x25>;
+		};
+
+		qpool6: qman-pool at 6 {
+			cell-index = <6>;
+			compatible = "fsl,p5020-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x26>;
+		};
+
+		qpool7: qman-pool at 7 {
+			cell-index = <7>;
+			compatible = "fsl,p5020-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x27>;
+		};
+
+		qpool8: qman-pool at 8 {
+			cell-index = <8>;
+			compatible = "fsl,p5020-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x28>;
+		};
+
+		qpool9: qman-pool at 9 {
+			cell-index = <9>;
+			compatible = "fsl,p5020-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x29>;
+		};
+
+		qpool10: qman-pool at 10 {
+			cell-index = <10>;
+			compatible = "fsl,p5020-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x2a>;
+		};
+
+		qpool11: qman-pool at 11 {
+			cell-index = <11>;
+			compatible = "fsl,p5020-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x2b>;
+		};
+
+		qpool12: qman-pool at 12 {
+			cell-index = <12>;
+			compatible = "fsl,p5020-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x2c>;
+		};
+
+		qpool13: qman-pool at 13 {
+			cell-index = <13>;
+			compatible = "fsl,p5020-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x2d>;
+		};
+
+		qpool14: qman-pool at 14 {
+			cell-index = <14>;
+			compatible = "fsl,p5020-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x2e>;
+		};
+
+		qpool15: qman-pool at 15 {
+			cell-index = <15>;
+			compatible = "fsl,p5020-qman-pool-channel", "fsl,qman-pool-channel";
+			fsl,qman-channel-id = <0x2f>;
+		};
+	};
+
+	soc: soc at ffe000000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		device_type = "soc";
+		compatible = "simple-bus";
+		
+		bus-frequency = <0>;	// Filled out by kernel.
+		
+		ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
+		reg = <0xf 0xfe000000 0 0x00001000>;
+
+		soc-sram-error {
+			compatible = "fsl,soc-sram-error";
+			interrupts = <16 2 1 29>;
+		};
+
+		corenet-law at 0 {
+			compatible = "fsl,corenet-law";
+			reg = <0x0 0x1000>;
+			fsl,num-laws = <32>;
+		};
+
+		ddr1: memory-controller at 8000 {
+			compatible = "fsl,qoriq-memory-controller-v4.5", "fsl,qoriq-memory-controller";
+			reg = <0x8000 0x1000>;
+			interrupts = <16 2 1 23>;
+		};
+
+		ddr2: memory-controller at 9000 {
+			compatible = "fsl,qoriq-memory-controller-v4.5", "fsl,qoriq-memory-controller";
+			reg = <0x9000 0x1000>;
+			interrupts = <16 2 1 22>;
+		};
+
+		cpc: l3-cache-controller at 10000 {
+			compatible = "fsl,p5020-l3-cache-controller", "fsl,p4080-l3-cache-controller", "cache";
+			reg = <0x10000 0x1000
+			       0x11000 0x1000>;
+			interrupts = <16 2 1 27
+				      16 2 1 26>;
+		};
+
+		corenet-cf at 18000 {
+			compatible = "fsl,corenet-cf";
+			reg = <0x18000 0x1000>;
+			interrupts = <16 2 1 31>;
+			fsl,ccf-num-csdids = <32>;
+			fsl,ccf-num-snoopids = <32>;
+		};
+
+		iommu at 20000 {
+			compatible = "fsl,pamu-v1.0", "fsl,pamu";
+			reg = <0x20000 0x4000>;
+			interrupts = <
+				24 2 0 0
+				16 2 1 30>;
+		};
+
+		mpic: pic at 40000 {
+			clock-frequency = <0>;
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <4>;
+			reg = <0x40000 0x40000>;
+			compatible = "fsl,mpic", "chrp,open-pic";
+			device_type = "open-pic";
+		};
+
+		msi0: msi at 41600 {
+			compatible = "fsl,mpic-msi";
+			reg = <0x41600 0x200>;
+			msi-available-ranges = <0 0x100>;
+			interrupts = <
+				0xe0 0 0 0
+				0xe1 0 0 0
+				0xe2 0 0 0
+				0xe3 0 0 0
+				0xe4 0 0 0
+				0xe5 0 0 0
+				0xe6 0 0 0
+				0xe7 0 0 0>;
+		};
+
+		msi1: msi at 41800 {
+			compatible = "fsl,mpic-msi";
+			reg = <0x41800 0x200>;
+			msi-available-ranges = <0 0x100>;
+			interrupts = <
+				0xe8 0 0 0
+				0xe9 0 0 0
+				0xea 0 0 0
+				0xeb 0 0 0
+				0xec 0 0 0
+				0xed 0 0 0
+				0xee 0 0 0
+				0xef 0 0 0>;
+		};
+
+		msi2: msi at 41a00 {
+			compatible = "fsl,mpic-msi";
+			reg = <0x41a00 0x200>;
+			msi-available-ranges = <0 0x100>;
+			interrupts = <
+				0xf0 0 0 0
+				0xf1 0 0 0
+				0xf2 0 0 0
+				0xf3 0 0 0
+				0xf4 0 0 0
+				0xf5 0 0 0
+				0xf6 0 0 0
+				0xf7 0 0 0>;
+		};
+
+		guts: global-utilities at e0000 {
+			compatible = "fsl,qoriq-device-config-1.0";
+			reg = <0xe0000 0xe00>;
+			fsl,has-rstcr;
+			#sleep-cells = <1>;
+			fsl,liodn-bits = <12>;
+		};
+
+		pins: global-utilities at e0e00 {
+			compatible = "fsl,qoriq-pin-control-1.0";
+			reg = <0xe0e00 0x200>;
+			#sleep-cells = <2>;
+		};
+
+		clockgen: global-utilities at e1000 {
+			compatible = "fsl,p5020-clockgen", "fsl,qoriq-clockgen-1.0";
+			reg = <0xe1000 0x1000>;
+			clock-frequency = <0>;
+		};
+
+		rcpm: global-utilities at e2000 {
+			compatible = "fsl,qoriq-rcpm-1.0";
+			reg = <0xe2000 0x1000>;
+			#sleep-cells = <1>;
+		};
+
+		sfp: sfp at e8000 {
+			compatible = "fsl,p5020-sfp", "fsl,qoriq-sfp-1.0";
+			reg	   = <0xe8000 0x1000>;
+		};
+
+		serdes: serdes at ea000 {
+			compatible = "fsl,p5020-serdes";
+			reg	   = <0xea000 0x1000>;
+		};
+
+		dma0: dma at 100300 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "fsl,p5020-dma", "fsl,eloplus-dma";
+			reg = <0x100300 0x4>;
+			ranges = <0x0 0x100100 0x200>;
+			cell-index = <0>;
+			dma-channel at 0 {
+				compatible = "fsl,p5020-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x0 0x80>;
+				cell-index = <0>;
+				interrupts = <28 2 0 0>;
+			};
+			dma-channel at 80 {
+				compatible = "fsl,p5020-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x80 0x80>;
+				cell-index = <1>;
+				interrupts = <29 2 0 0>;
+			};
+			dma-channel at 100 {
+				compatible = "fsl,p5020-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x100 0x80>;
+				cell-index = <2>;
+				interrupts = <30 2 0 0>;
+			};
+			dma-channel at 180 {
+				compatible = "fsl,p5020-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x180 0x80>;
+				cell-index = <3>;
+				interrupts = <31 2 0 0>;
+			};
+		};
+
+		dma1: dma at 101300 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "fsl,p5020-dma", "fsl,eloplus-dma";
+			reg = <0x101300 0x4>;
+			ranges = <0x0 0x101100 0x200>;
+			cell-index = <1>;
+			dma-channel at 0 {
+				compatible = "fsl,p5020-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x0 0x80>;
+				cell-index = <0>;
+				interrupts = <32 2 0 0>;
+			};
+			dma-channel at 80 {
+				compatible = "fsl,p5020-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x80 0x80>;
+				cell-index = <1>;
+				interrupts = <33 2 0 0>;
+			};
+			dma-channel at 100 {
+				compatible = "fsl,p5020-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x100 0x80>;
+				cell-index = <2>;
+				interrupts = <34 2 0 0>;
+			};
+			dma-channel at 180 {
+				compatible = "fsl,p5020-dma-channel",
+						"fsl,eloplus-dma-channel";
+				reg = <0x180 0x80>;
+				cell-index = <3>;
+				interrupts = <35 2 0 0>;
+			};
+		};
+
+		spi at 110000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,p5020-espi", "fsl,mpc8536-espi";
+			reg = <0x110000 0x1000>;
+			interrupts = <53 0x2 0 0>;
+			fsl,espi-num-chipselects = <4>;
+		};
+
+		sdhc: sdhc at 114000 {
+			compatible = "fsl,p5020-esdhc", "fsl,esdhc";
+			reg = <0x114000 0x1000>;
+			interrupts = <48 2 0 0>;
+			sdhci,auto-cmd12;
+			clock-frequency = <0>;
+		};
+
+		i2c at 118000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			cell-index = <0>;
+			compatible = "fsl-i2c";
+			reg = <0x118000 0x100>;
+			interrupts = <38 2 0 0>;
+			dfsrr;
+		};
+
+		i2c at 118100 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			cell-index = <1>;
+			compatible = "fsl-i2c";
+			reg = <0x118100 0x100>;
+			interrupts = <38 2 0 0>;
+			dfsrr;
+		};
+
+		i2c at 119000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			cell-index = <2>;
+			compatible = "fsl-i2c";
+			reg = <0x119000 0x100>;
+			interrupts = <39 2 0 0>;
+			dfsrr;
+		};
+
+		i2c at 119100 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			cell-index = <3>;
+			compatible = "fsl-i2c";
+			reg = <0x119100 0x100>;
+			interrupts = <39 2 0 0>;
+			dfsrr;
+		};
+
+		serial0: serial at 11c500 {
+			cell-index = <0>;
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <0x11c500 0x100>;
+			clock-frequency = <0>;
+			interrupts = <36 2 0 0>;
+		};
+
+		serial1: serial at 11c600 {
+			cell-index = <1>;
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <0x11c600 0x100>;
+			clock-frequency = <0>;
+			interrupts = <36 2 0 0>;
+		};
+
+		serial2: serial at 11d500 {
+			cell-index = <2>;
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <0x11d500 0x100>;
+			clock-frequency = <0>;
+			interrupts = <37 2 0 0>;
+		};
+
+		serial3: serial at 11d600 {
+			cell-index = <3>;
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <0x11d600 0x100>;
+			clock-frequency = <0>;
+			interrupts = <37 2 0 0>;
+		};
+
+		gpio0: gpio at 130000 {
+			compatible = "fsl,p5020-gpio", "fsl,qoriq-gpio";
+			reg = <0x130000 0x1000>;
+			interrupts = <55 2 0 0>;
+			#gpio-cells = <2>;
+			gpio-controller;
+		};
+
+		rman: rman at 1e0000 {
+			compatible = "fsl,rman";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x0 0x1e0000 0x20000>;
+			reg = <0x1e0000 0x20000>;
+			interrupts = <16 2 1 11>; /* err_irq */
+			fsl,qman-channels-id = <0x62 0x63>;
+
+			inbound-block at 0 {
+				compatible = "fsl,rman-inbound-block";
+				reg = <0x0 0x800>;
+			};
+			global-cfg at b00 {
+				compatible = "fsl,rman-global-cfg";
+				reg = <0xb00 0x500>;
+			};
+			inbound-block at 1000 {
+				compatible = "fsl,rman-inbound-block";
+				reg = <0x1000 0x800>;
+			};
+			inbound-block at 2000 {
+				compatible = "fsl,rman-inbound-block";
+				reg = <0x2000 0x800>;
+			};
+			inbound-block at 3000 {
+				compatible = "fsl,rman-inbound-block";
+				reg = <0x3000 0x800>;
+			};
+		};
+
+		usb0: usb at 210000 {
+			compatible = "fsl,p5020-usb2-mph",
+					"fsl,mpc85xx-usb2-mph", "fsl-usb2-mph";
+			reg = <0x210000 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			interrupts = <44 0x2 0 0>;
+			phy_type = "utmi";
+			port0;
+		};
+
+		usb1: usb at 211000 {
+			compatible = "fsl,p5020-usb2-dr",
+					"fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
+			reg = <0x211000 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			interrupts = <45 0x2 0 0>;
+			dr_mode = "host";
+			phy_type = "utmi";
+		};
+
+		sata at 220000 {
+			compatible = "fsl,p5020-sata", "fsl,pq-sata-v2";
+			reg = <0x220000 0x1000>;
+			interrupts = <68 0x2 0 0>;
+		};
+
+		sata at 221000 {
+			compatible = "fsl,p5020-sata", "fsl,pq-sata-v2";
+			reg = <0x221000 0x1000>;
+			interrupts = <69 0x2 0 0>;
+		};
+
+		crypto: crypto at 300000 {
+			compatible = "fsl,sec-v4.2", "fsl,sec-v4.0";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg		 = <0x300000 0x10000>;
+			ranges		 = <0 0x300000 0x10000>;
+			interrupts	 = <92 2 0 0>;
+
+			sec_jr0: jr at 1000 {
+				compatible = "fsl,sec-v4.2-job-ring",
+					     "fsl,sec-v4.0-job-ring";
+				reg = <0x1000 0x1000>;
+				interrupts = <88 2 0 0>;
+			};
+
+			sec_jr1: jr at 2000 {
+				compatible = "fsl,sec-v4.2-job-ring",
+					     "fsl,sec-v4.0-job-ring";
+				reg = <0x2000 0x1000>;
+				interrupts = <89 2 0 0>;
+			};
+
+			sec_jr2: jr at 3000 {
+				compatible = "fsl,sec-v4.2-job-ring",
+					     "fsl,sec-v4.0-job-ring";
+				reg = <0x3000 0x1000>;
+				interrupts = <90 2 0 0>;
+			};
+
+			sec_jr3: jr at 4000 {
+				compatible = "fsl,sec-v4.2-job-ring",
+					     "fsl,sec-v4.0-job-ring";
+				reg = <0x4000 0x1000>;
+				interrupts = <91 2 0 0>;
+			};
+
+			rtic at 6000 {
+				compatible = "fsl,sec-v4.2-rtic",
+					     "fsl,sec-v4.0-rtic";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				reg = <0x6000 0x100>;
+				ranges = <0x0 0x6100 0xe00>;
+
+				rtic_a: rtic-a at 0 {
+					compatible = "fsl,sec-v4.2-rtic-memory",
+						     "fsl,sec-v4.0-rtic-memory";
+					reg = <0x00 0x20 0x100 0x80>;
+				};
+
+				rtic_b: rtic-b at 20 {
+					compatible = "fsl,sec-v4.2-rtic-memory",
+						     "fsl,sec-v4.0-rtic-memory";
+					reg = <0x20 0x20 0x200 0x80>;
+				};
+
+				rtic_c: rtic-c at 40 {
+					compatible = "fsl,sec-v4.2-rtic-memory",
+						     "fsl,sec-v4.0-rtic-memory";
+					reg = <0x40 0x20 0x300 0x80>;
+				};
+
+				rtic_d: rtic-d at 60 {
+					compatible = "fsl,sec-v4.2-rtic-memory",
+						     "fsl,sec-v4.0-rtic-memory";
+					reg = <0x60 0x20 0x500 0x80>;
+				};
+			};
+		};
+
+		sec_mon: sec_mon at 314000 {
+			compatible = "fsl,sec-v4.2-mon", "fsl,sec-v4.0-mon";
+			reg = <0x314000 0x1000>;
+			interrupts = <93 2 0 0>;
+		};
+
+		raideng: raideng at 320000 {
+			compatible = "fsl,raideng-v1.0";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0x320000 0x10000>;
+			ranges = <0 0x320000 0x10000>;
+
+			raideng_jq0 at 1000 {
+				compatible = "fsl,raideng-v1.0-job-queue";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				reg = <0x1000 0x1000>;
+				ranges = <0x0 0x1000 0x1000>;
+
+				raideng_jr0: jr at 0 {
+					compatible = "fsl,raideng-v1.0-job-ring", "fsl,raideng-v1.0-hp-ring";
+					reg = <0x0 0x400>;
+					interrupts = <139 2 0 0>;
+					interrupt-parent = <&mpic>;
+				};
+
+				raideng_jr1: jr at 400 {
+					compatible = "fsl,raideng-v1.0-job-ring", "fsl,raideng-v1.0-lp-ring";
+					reg = <0x400 0x400>;
+					interrupts = <140 2 0 0>;
+					interrupt-parent = <&mpic>;
+				};
+			};
+
+			raideng_jq1 at 2000 {
+				compatible = "fsl,raideng-v1.0-job-queue";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				reg = <0x2000 0x1000>;
+				ranges = <0x0 0x2000 0x1000>;
+
+				raideng_jr2: jr at 0 {
+					compatible = "fsl,raideng-v1.0-job-ring", "fsl,raideng-v1.0-hp-ring";
+					reg = <0x0 0x400>;
+					interrupts = <141 2 0 0>;
+					interrupt-parent = <&mpic>;
+				};
+
+				raideng_jr3: jr at 400 {
+					compatible = "fsl,raideng-v1.0-job-ring", "fsl,raideng-v1.0-lp-ring";
+					reg = <0x400 0x400>;
+					interrupts = <142 2 0 0>;
+					interrupt-parent = <&mpic>;
+				};
+			};
+		};
+
+		pme: pme at 316000 {
+			compatible = "fsl,pme";
+			reg = <0x316000 0x10000>;
+			/* fsl,pme-pdsr = <0x0 0x23000000 0x0 0x01000000>; */
+			/* fsl,pme-sre = <0x0 0x24000000 0x0 0x00a00000>; */
+			interrupts = <16 2 1 5>;
+		};
+
+		qman: qman at 318000 {
+			compatible = "fsl,p5020-qman", "fsl,qman";
+			reg = <0x318000 0x1000>;
+			interrupts = <16 2 1 3>;
+			/* Commented out, use default allocation */
+			/* fsl,qman-fqd = <0x0 0x20000000 0x0 0x01000000>; */
+			/* fsl,qman-pfdr = <0x0 0x21000000 0x0 0x01000000>; */
+		};
+
+		bman: bman at 31a000 {
+			compatible = "fsl,p5020-bman", "fsl,bman";
+			reg = <0x31a000 0x1000>;
+			interrupts = <16 2 1 2>;
+			/* Same as fsl,qman-*, use default allocation */
+			/* fsl,bman-fbpr = <0x0 0x22000000 0x0 0x01000000>; */
+		};
+
+		fman0: fman at 400000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			cell-index = <0>;
+			compatible = "fsl,p5020-fman", "fsl,fman", "simple-bus";
+			ranges = <0 0x400000 0x100000>;
+			reg = <0x400000 0x100000>;
+			clock-frequency = <0>;
+			interrupts = <
+				96 2 0 0
+				16 2 1 1>;
+
+			cc at 0 {
+				compatible = "fsl,p5020-fman-cc", "fsl,fman-cc";
+			};
+
+			parser at c7000 {
+				compatible = "fsl,p5020-fman-parser", "fsl,fman-parser";
+				reg = <0xc7000 0x1000>;
+			};
+
+			keygen at c1000 {
+				compatible = "fsl,p5020-fman-keygen", "fsl,fman-keygen";
+				reg = <0xc1000 0x1000>;
+			};
+
+			policer at c0000 {
+				compatible = "fsl,p5020-fman-policer", "fsl,fman-policer";
+				reg = <0xc0000 0x1000>;
+			};
+
+			muram at 0 {
+				compatible = "fsl,p5020-fman-muram", "fsl,fman-muram";
+				reg = <0x0 0x28000>;
+			};
+
+			bmi at 80000 {
+				compatible = "fsl,p5020-fman-bmi", "fsl,fman-bmi";
+				reg = <0x80000 0x400>;
+			};
+
+			qmi at 80400 {
+				compatible = "fsl,p5020-fman-qmi", "fsl,fman-qmi";
+				reg = <0x80400 0x400>;
+			};
+
+			fman0_rx0: port at 88000 {
+				cell-index = <0>;
+				compatible = "fsl,p5020-fman-port-1g-rx", "fsl,fman-port-1g-rx";
+				reg = <0x88000 0x1000>;
+			};
+			fman0_rx1: port at 89000 {
+				cell-index = <1>;
+				compatible = "fsl,p5020-fman-port-1g-rx", "fsl,fman-port-1g-rx";
+				reg = <0x89000 0x1000>;
+			};
+			fman0_rx2: port at 8a000 {
+				cell-index = <2>;
+				compatible = "fsl,p5020-fman-port-1g-rx", "fsl,fman-port-1g-rx";
+				reg = <0x8a000 0x1000>;
+			};
+			fman0_rx3: port at 8b000 {
+				cell-index = <3>;
+				compatible = "fsl,p5020-fman-port-1g-rx", "fsl,fman-port-1g-rx";
+				reg = <0x8b000 0x1000>;
+			};
+			fman0_rx4: port at 8c000 {
+				cell-index = <4>;
+				compatible = "fsl,p5020-fman-port-1g-rx", "fsl,fman-port-1g-rx";
+				reg = <0x8c000 0x1000>;
+			};
+			fman0_rx5: port at 90000 {
+				cell-index = <0>;
+				compatible = "fsl,p5020-fman-port-10g-rx", "fsl,fman-port-10g-rx";
+				reg = <0x90000 0x1000>;
+			};
+
+			fman0_tx5: port at b0000 {
+				cell-index = <0>;
+				compatible = "fsl,p5020-fman-port-10g-tx", "fsl,fman-port-10g-tx";
+				reg = <0xb0000 0x1000>;
+				fsl,qman-channel-id = <0x40>;
+			};
+			fman0_tx0: port at a8000 {
+				cell-index = <0>;
+				compatible = "fsl,p5020-fman-port-1g-tx", "fsl,fman-port-1g-tx";
+				reg = <0xa8000 0x1000>;
+				fsl,qman-channel-id = <0x41>;
+			};
+			fman0_tx1: port at a9000 {
+				cell-index = <1>;
+				compatible = "fsl,p5020-fman-port-1g-tx", "fsl,fman-port-1g-tx";
+				reg = <0xa9000 0x1000>;
+				fsl,qman-channel-id = <0x42>;
+			};
+			fman0_tx2: port at aa000 {
+				cell-index = <2>;
+				compatible = "fsl,p5020-fman-port-1g-tx", "fsl,fman-port-1g-tx";
+				reg = <0xaa000 0x1000>;
+				fsl,qman-channel-id = <0x43>;
+			};
+			fman0_tx3: port at ab000 {
+				cell-index = <3>;
+				compatible = "fsl,p5020-fman-port-1g-tx", "fsl,fman-port-1g-tx";
+				reg = <0xab000 0x1000>;
+				fsl,qman-channel-id = <0x44>;
+			};
+			fman0_tx4: port at ac000 {
+				cell-index = <4>;
+				compatible = "fsl,p5020-fman-port-1g-tx", "fsl,fman-port-1g-tx";
+				reg = <0xac000 0x1000>;
+				fsl,qman-channel-id = <0x45>;
+			};
+
+			fman0_oh0: port at 81000 {
+				cell-index = <0>;
+				compatible = "fsl,p5020-fman-port-oh", "fsl,fman-port-oh";
+				reg = <0x81000 0x1000>;
+				fsl,qman-channel-id = <0x46>;
+			};
+			fman0_oh1: port at 82000 {
+				cell-index = <1>;
+				compatible = "fsl,p5020-fman-port-oh", "fsl,fman-port-oh";
+				reg = <0x82000 0x1000>;
+				fsl,qman-channel-id = <0x47>;
+			};
+			fman0_oh2: port at 83000 {
+				cell-index = <2>;
+				compatible = "fsl,p5020-fman-port-oh", "fsl,fman-port-oh";
+				reg = <0x83000 0x1000>;
+				fsl,qman-channel-id = <0x48>;
+			};
+			fman0_oh3: port at 84000 {
+				cell-index = <3>;
+				compatible = "fsl,p5020-fman-port-oh", "fsl,fman-port-oh";
+				reg = <0x84000 0x1000>;
+				fsl,qman-channel-id = <0x49>;
+			};
+			fman0_oh4: port at 85000 {
+				cell-index = <4>;
+				compatible = "fsl,p5020-fman-port-oh", "fsl,fman-port-oh";
+				reg = <0x85000 0x1000>;
+				fsl,qman-channel-id = <0x4a>;
+			};
+			fman0_oh5: port at 86000 {
+				cell-index = <5>;
+				compatible = "fsl,p5020-fman-port-oh", "fsl,fman-port-oh";
+				reg = <0x86000 0x1000>;
+				fsl,qman-channel-id = <0x4b>;
+			};
+			fman0_oh6: port at 87000 {
+				cell-index = <6>;
+				compatible = "fsl,p5020-fman-port-oh", "fsl,fman-port-oh";
+				reg = <0x87000 0x1000>;
+			};
+
+			enet0: ethernet at e0000 {
+				cell-index = <0>;
+				compatible = "fsl,p5020-fman-1g-mac", "fsl,fman-1g-mac";
+				reg = <0xe0000 0x1000>;
+				fsl,port-handles = <&fman0_rx0 &fman0_tx0>;
+				ptimer-handle = <&ptp_timer0>;
+			};
+
+			mdio0: mdio at e1120 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,fman-mdio";
+				reg = <0xe1120 0xee0>;
+				interrupts = <100 1 0 0>;
+			};
+
+			enet1: ethernet at e2000 {
+				cell-index = <1>;
+				compatible = "fsl,p5020-fman-1g-mac", "fsl,fman-1g-mac";
+				reg = <0xe2000 0x1000>;
+				fsl,port-handles = <&fman0_rx1 &fman0_tx1>;
+				ptimer-handle = <&ptp_timer0>;
+			};
+
+			mdio at e3120 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,fman-tbi";
+				reg = <0xe3120 0xee0>;
+				interrupts = <100 1 0 0>;
+			};
+
+			enet2: ethernet at e4000 {
+				cell-index = <2>;
+				compatible = "fsl,p5020-fman-1g-mac", "fsl,fman-1g-mac";
+				reg = <0xe4000 0x1000>;
+				fsl,port-handles = <&fman0_rx2 &fman0_tx2>;
+				ptimer-handle = <&ptp_timer0>;
+			};
+
+			mdio at e5120 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,fman-tbi";
+				reg = <0xe5120 0xee0>;
+				interrupts = <100 1 0 0>;
+			};
+
+			enet3: ethernet at e6000 {
+				cell-index = <3>;
+				compatible = "fsl,p5020-fman-1g-mac", "fsl,fman-1g-mac";
+				reg = <0xe6000 0x1000>;
+				fsl,port-handles = <&fman0_rx3 &fman0_tx3>;
+				ptimer-handle = <&ptp_timer0>;
+			};
+
+			mdio at e7120 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,fman-tbi";
+				reg = <0xe7120 0xee0>;
+				interrupts = <100 1 0 0>;
+			};
+
+			enet4: ethernet at e8000 {
+				cell-index = <4>;
+				compatible = "fsl,p5020-fman-1g-mac", "fsl,fman-1g-mac";
+				reg = <0xe8000 0x1000>;
+				fsl,port-handles = <&fman0_rx4 &fman0_tx4>;
+				ptimer-handle = <&ptp_timer0>;
+			};
+
+			mdio at e9120 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,fman-tbi";
+				reg = <0xe9120 0xee0>;
+				interrupts = <100 1 0 0>;
+			};
+
+			enet5: ethernet at f0000 {
+				cell-index = <0>;
+				compatible = "fsl,p5020-fman-10g-mac", "fsl,fman-10g-mac";
+				reg = <0xf0000 0x1000>;
+				fsl,port-handles = <&fman0_rx5 &fman0_tx5>;
+			};
+
+			mdio at f1000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,fman-xmdio";
+				reg = <0xf1000 0x1000>;
+				interrupts = <100 1 0 0>;
+			};
+
+			ptp_timer0: rtc at fe000 {
+				compatible = "fsl,fman-rtc";
+				reg = <0xfe000 0x1000>;
+			};
+		};
+	};
+
+	rapidio at ffe0c0000 {
+		compatible = "fsl,srio";
+		interrupts = <16 2 1 11>;
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		port1 {
+			#address-cells = <2>;
+			#size-cells = <2>;
+			cell-index = <1>;
+		};
+
+		port2 {
+			#address-cells = <2>;
+			#size-cells = <2>;
+			cell-index = <2>;
+		};
+	};
+
+	localbus at ffe124000 {
+		compatible = "fsl,p5020-rev1.0-elbc", "simple-bus", "fsl,elbc";
+		interrupts = <
+			25 2 0 0
+			16 2 1 19
+			>;
+		#address-cells = <2>;
+		#size-cells = <1>;
+	};
+
+	pci0: pcie at ffe200000 {
+		compatible = "fsl,p5020-pcie", "fsl,qoriq-pcie-v2.2";
+		device_type = "pci";
+		status = "okay";
+		#size-cells = <2>;
+		#address-cells = <3>;
+		cell-index = <0>;
+		bus-range = <0x0 0xff>;
+		clock-frequency = <0x1fca055>;
+		fsl,msi = <&msi0>;
+		interrupts = <16 2 1 15>;
+
+		pcie at 0 {
+			reg = <0 0 0 0 0>;
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			device_type = "pci";
+			interrupts = <16 2 1 15>;
+			interrupt-map-mask = <0xf800 0 0 7>;
+			interrupt-map = <
+				/* IDSEL 0x0 */
+				0000 0 0 1 &mpic 40 1 0 0
+				0000 0 0 2 &mpic 1 1 0 0
+				0000 0 0 3 &mpic 2 1 0 0
+				0000 0 0 4 &mpic 3 1 0 0
+				>;
+		};
+	};
+
+	pci1: pcie at ffe201000 {
+		compatible = "fsl,p5020-pcie", "fsl,qoriq-pcie-v2.2";
+		device_type = "pci";
+		status = "disabled";
+		#size-cells = <2>;
+		#address-cells = <3>;
+		cell-index = <1>;
+		bus-range = <0 0xff>;
+		clock-frequency = <0x1fca055>;
+		fsl,msi = <&msi1>;
+		interrupts = <16 2 1 14>;
+		pcie at 0 {
+			reg = <0 0 0 0 0>;
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			device_type = "pci";
+			interrupts = <16 2 1 14>;
+			interrupt-map-mask = <0xf800 0 0 7>;
+			interrupt-map = <
+				/* IDSEL 0x0 */
+				0000 0 0 1 &mpic 41 1 0 0
+				0000 0 0 2 &mpic 5 1 0 0
+				0000 0 0 3 &mpic 6 1 0 0
+				0000 0 0 4 &mpic 7 1 0 0
+				>;
+		};
+	};
+
+	pci2: pcie at ffe202000 {
+		compatible = "fsl,p5020-pcie", "fsl,qoriq-pcie-v2.2";
+		device_type = "pci";
+		status = "okay";
+		#size-cells = <2>;
+		#address-cells = <3>;
+		cell-index = <2>;
+		bus-range = <0x0 0xff>;
+		clock-frequency = <0x1fca055>;
+		fsl,msi = <&msi2>;
+		interrupts = <16 2 1 13>;
+		pcie at 0 {
+			reg = <0 0 0 0 0>;
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			device_type = "pci";
+			interrupts = <16 2 1 13>;
+			interrupt-map-mask = <0xf800 0 0 7>;
+			interrupt-map = <
+				/* IDSEL 0x0 */
+				0000 0 0 1 &mpic 42 1 0 0
+				0000 0 0 2 &mpic 9 1 0 0
+				0000 0 0 3 &mpic 10 1 0 0
+				0000 0 0 4 &mpic 11 1 0 0
+				>;
+		};
+	};
+
+	pci3: pcie at ffe203000 {
+		compatible = "fsl,p5020-pcie", "fsl,qoriq-pcie-v2.2";
+		device_type = "pci";
+		status = "disabled";
+		#size-cells = <2>;
+		#address-cells = <3>;
+		cell-index = <3>;
+		bus-range = <0x0 0xff>;
+		clock-frequency = <0x1fca055>;
+		fsl,msi = <&msi2>;
+		interrupts = <16 2 1 12>;
+		pcie at 0 {
+			reg = <0 0 0 0 0>;
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			device_type = "pci";
+			interrupts = <16 2 1 12>;
+			interrupt-map-mask = <0xf800 0 0 7>;
+			interrupt-map = <
+				/* IDSEL 0x0 */
+				0000 0 0 1 &mpic 43 1 0 0
+				0000 0 0 2 &mpic 0 1 0 0
+				0000 0 0 3 &mpic 4 1 0 0
+				0000 0 0 4 &mpic 8 1 0 0
+				>;
+		};
+	};
+};
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/fdt/dts/sheevaplug.dts
--- a/head/sys/boot/fdt/dts/sheevaplug.dts	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/fdt/dts/sheevaplug.dts	Wed Jul 25 16:45:04 2012 +0300
@@ -28,7 +28,7 @@
  *
  * Marvell SheevaPlug Device Tree Source.
  *
- * $FreeBSD: head/sys/boot/fdt/dts/sheevaplug.dts 227730 2011-11-19 16:30:06Z raj $
+ * $FreeBSD: head/sys/boot/fdt/dts/sheevaplug.dts 235778 2012-05-22 08:33:14Z gber $
  */
 
 /dts-v1/;
@@ -71,48 +71,33 @@
 		reg = <0x0 0x20000000>;		// 512M at 0x0
 	};
 
-	localbus at f1000000 {
+	localbus at 0 {
 		#address-cells = <2>;
 		#size-cells = <1>;
 		compatible = "mrvl,lbc";
+		bank-count = <3>;
 
 		/* This reflects CPU decode windows setup. */
-		ranges = <0x0 0x0f 0xf9300000 0x00100000
-			  0x1 0x1e 0xfa000000 0x00100000
-			  0x2 0x1d 0xfa100000 0x02000000
-			  0x3 0x1b 0xfc100000 0x00000400>;
+		ranges = <0x0 0x2f 0xf9300000 0x00100000>;
 
-		nor at 0,0 {
+		nand at 0,0 {
 			#address-cells = <1>;
 			#size-cells = <1>;
-			compatible = "cfi-flash";
+			compatible = "mrvl,nfc";
 			reg = <0x0 0x0 0x00100000>;
 			bank-width = <2>;
 			device-width = <1>;
-		};
 
-		led at 1,0 {
-			#address-cells = <1>;
-			#size-cells = <1>;
-			compatible = "led";
-			reg = <0x1 0x0 0x00100000>;
-		};
+			slice at 0 {
+				reg = <0x0 0x200000>;
+				label = "u-boot";
+				read-only;
+			};
 
-		nor at 2,0 {
-			#address-cells = <1>;
-			#size-cells = <1>;
-			compatible = "cfi-flash";
-			reg = <0x2 0x0 0x02000000>;
-			bank-width = <2>;
-			device-width = <1>;
-		};
-
-		nand at 3,0 {
-			#address-cells = <1>;
-			#size-cells = <1>;
-			reg = <0x3 0x0 0x00100000>;
-			bank-width = <2>;
-			device-width = <1>;
+			slice at 200000 {
+				reg = <0x200000 0x1fe00000>;
+				label = "root";
+			};
 		};
 	};
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/fdt/fdt_loader_cmd.c
--- a/head/sys/boot/fdt/fdt_loader_cmd.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/fdt/fdt_loader_cmd.c	Wed Jul 25 16:45:04 2012 +0300
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/boot/fdt/fdt_loader_cmd.c 233323 2012-03-22 20:34:26Z raj $");
+__FBSDID("$FreeBSD: head/sys/boot/fdt/fdt_loader_cmd.c 235529 2012-05-17 04:04:48Z kientzle $");
 
 #include <stand.h>
 #include <fdt.h>
@@ -57,11 +57,17 @@
 #define STR(number) #number
 #define STRINGIFY(number) STR(number)
 
-#define COPYOUT(s,d,l)	archsw.arch_copyout((vm_offset_t)(s), d, l)
+#define COPYOUT(s,d,l)	archsw.arch_copyout(s, d, l)
+#define COPYIN(s,d,l)	archsw.arch_copyin(s, d, l)
 
 #define FDT_STATIC_DTB_SYMBOL	"fdt_static_dtb"
 
+/* Local copy of FDT */
 static struct fdt_header *fdtp = NULL;
+/* Size of FDT blob */
+static size_t fdtp_size = 0;
+/* Location of FDT in kernel or module */
+static vm_offset_t fdtp_va = 0;
 
 static int fdt_cmd_nyi(int argc, char *argv[]);
 
@@ -98,21 +104,19 @@
 static char cwd[FDT_CWD_LEN] = "/";
 
 static vm_offset_t
-fdt_find_static_dtb(void)
+fdt_find_static_dtb()
 {
+	Elf_Dyn dyn;
 	Elf_Sym sym;
-	vm_offset_t dyntab, esym;
+	vm_offset_t dyntab, esym, strtab, symtab, fdt_start;
 	uint64_t offs;
 	struct preloaded_file *kfp;
 	struct file_metadata *md;
-	Elf_Sym *symtab;
-	Elf_Dyn *dyn;
-	char *strtab, *strp;
-	int i, sym_count;
+	char *strp;
+	int sym_count;
 
-	symtab = NULL;
-	dyntab = esym = 0;
-	strtab = strp = NULL;
+	symtab = strtab = dyntab = esym = 0;
+	strp = NULL;
 
 	offs = __elfN(relocation_offset);
 
@@ -123,28 +127,29 @@
 	md = file_findmetadata(kfp, MODINFOMD_ESYM);
 	if (md == NULL)
 		return (0);
-	COPYOUT(md->md_data, &esym, sizeof(esym));
+	bcopy(md->md_data, &esym, sizeof(esym));
+	// esym is already offset
 
 	md = file_findmetadata(kfp, MODINFOMD_DYNAMIC);
 	if (md == NULL)
 		return (0);
-	COPYOUT(md->md_data, &dyntab, sizeof(dyntab));
-
+	bcopy(md->md_data, &dyntab, sizeof(dyntab));
 	dyntab += offs;
 
 	/* Locate STRTAB and DYNTAB */
-	for (dyn = (Elf_Dyn *)dyntab; dyn->d_tag != DT_NULL; dyn++) {
-		if (dyn->d_tag == DT_STRTAB) {
-			strtab = (char *)(uintptr_t)(dyn->d_un.d_ptr + offs);
-			continue;
-		} else if (dyn->d_tag == DT_SYMTAB) {
-			symtab = (Elf_Sym *)(uintptr_t)
-			    (dyn->d_un.d_ptr + offs);
-			continue;
+	for (;;) {
+		COPYOUT(dyntab, &dyn, sizeof(dyn));
+		if (dyn.d_tag == DT_STRTAB) {
+			strtab = (vm_offset_t)(dyn.d_un.d_ptr) + offs;
+		} else if (dyn.d_tag == DT_SYMTAB) {
+			symtab = (vm_offset_t)(dyn.d_un.d_ptr) + offs;
+		} else if (dyn.d_tag == DT_NULL) {
+			break;
 		}
+		dyntab += sizeof(dyn);
 	}
 
-	if (symtab == NULL || strtab == NULL) {
+	if (symtab == 0 || strtab == 0) {
 		/*
 		 * No symtab? No strtab? That should not happen here,
 		 * and should have been verified during __elfN(loadimage).
@@ -153,7 +158,7 @@
 		return (0);
 	}
 
-	sym_count = (int)((Elf_Sym *)esym - symtab) / sizeof(Elf_Sym);
+	sym_count = (int)(esym - symtab) / sizeof(Elf_Sym);
 
 	/*
 	 * The most efficent way to find a symbol would be to calculate a
@@ -165,26 +170,27 @@
 	 * we are eliminating symbols type of which is not STT_NOTYPE, or(and)
 	 * those which binding attribute is not STB_GLOBAL.
 	 */
-	for (i = 0; i < sym_count; i++) {
-		COPYOUT(symtab + i, &sym, sizeof(sym));
+	fdt_start = 0;
+	while (sym_count > 0 && fdt_start == 0) {
+		COPYOUT(symtab, &sym, sizeof(sym));
+		symtab += sizeof(sym);
+		--sym_count;
 		if (ELF_ST_BIND(sym.st_info) != STB_GLOBAL ||
 		    ELF_ST_TYPE(sym.st_info) != STT_NOTYPE)
 			continue;
-
-		strp = strdupout((vm_offset_t)(strtab + sym.st_name));
-		if (strcmp(strp, FDT_STATIC_DTB_SYMBOL) == 0) {
-			/* Found a match ! */
-			free(strp);
-			return ((vm_offset_t)(sym.st_value + offs));
-		}
+		strp = strdupout(strtab + sym.st_name);
+		if (strcmp(strp, FDT_STATIC_DTB_SYMBOL) == 0)
+			fdt_start = (vm_offset_t)sym.st_value + offs;
 		free(strp);
 	}
-	return (0);
+	printf("fdt_start: 0x%08jX\n", (intmax_t)fdt_start);
+	return (fdt_start);
 }
 
 static int
 fdt_setup_fdtp()
 {
+	struct fdt_header header;
 	struct preloaded_file *bfp;
 	int err;
 
@@ -193,15 +199,26 @@
 	 */
 	bfp = file_findfile(NULL, "dtb");
 	if (bfp == NULL) {
-		if ((fdtp = (struct fdt_header *)fdt_find_static_dtb()) == 0) {
+		if ((fdtp_va = fdt_find_static_dtb()) == 0) {
 			command_errmsg = "no device tree blob found!";
+			printf("%s\n", command_errmsg);
 			return (CMD_ERROR);
 		}
 	} else {
 		/* Dynamic blob has precedence over static. */
-		fdtp = (struct fdt_header *)bfp->f_addr;
+		fdtp_va = bfp->f_addr;
 	}
 
+	COPYOUT(fdtp_va, &header, sizeof(header));
+	fdtp_size = fdt_totalsize(&header);
+	fdtp = malloc(fdtp_size);
+	if (fdtp == NULL) {
+		command_errmsg = "can't allocate memory for device tree copy";
+			printf("%s\n", command_errmsg);
+		return (CMD_ERROR);
+	}
+	COPYOUT(fdtp_va, fdtp, fdtp_size);
+
 	/*
 	 * Validate the blob.
 	 */
@@ -317,6 +334,8 @@
 
 	/* We want to modify every subnode of /cpus */
 	o = fdt_path_offset(fdtp, "/cpus");
+	if (o < 0)
+		return;
 
 	/* maxo should contain offset of node next to /cpus */
 	depth = 0;
@@ -545,7 +564,7 @@
 /*
  * Locate the blob, fix it up and return its location.
  */
-void *
+vm_offset_t
 fdt_fixup(void)
 {
 	const char *env;
@@ -561,7 +580,7 @@
 	err = fdt_setup_fdtp();
 	if (err) {
 		sprintf(command_errbuf, "No valid device tree blob found!");
-		return (NULL);
+		return (0);
 	}
 
 	/* Create /chosen node (if not exists) */
@@ -616,7 +635,9 @@
 	fdt_setprop(fdtp, chosen, "fixup-applied", NULL, 0);
 
 success:
-	return (fdtp);
+	/* Overwrite the FDT with the fixed version. */
+	COPYIN(fdtp, fdtp_va, fdtp_size);
+	return (fdtp_va);
 }
 
 int
@@ -634,7 +655,7 @@
 	/*
 	 * Check if uboot env vars were parsed already. If not, do it now.
 	 */
-	if (fdt_fixup() == NULL)
+	if (fdt_fixup() == 0)
 		return (CMD_ERROR);
 
 	/*
@@ -1151,6 +1172,8 @@
 		else
 			sprintf(command_errbuf,
 			    "Could not add/modify property!\n");
+	} else {
+		COPYIN(fdtp, fdtp_va, fdtp_size);
 	}
 	return (rv);
 }
@@ -1371,6 +1394,8 @@
 	if (rv) {
 		sprintf(command_errbuf, "could not delete node");
 		return (CMD_ERROR);
+	} else {
+		COPYIN(fdtp, fdtp_va, fdtp_size);
 	}
 	return (CMD_OK);
 }
@@ -1401,6 +1426,8 @@
 			sprintf(command_errbuf,
 			    "Could not add node!\n");
 		return (CMD_ERROR);
+	} else {
+		COPYIN(fdtp, fdtp_va, fdtp_size);
 	}
 	return (CMD_OK);
 }
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/forth/beastie.4th
--- a/head/sys/boot/forth/beastie.4th	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/forth/beastie.4th	Wed Jul 25 16:45:04 2012 +0300
@@ -1,6 +1,6 @@
 \ Copyright (c) 2003 Scott Long <scottl at freebsd.org>
 \ Copyright (c) 2003 Aleksander Fafula <alex at fafula.com>
-\ Copyright (c) 2006-2011 Devin Teske <devinteske at hotmail.com>
+\ Copyright (c) 2006-2011 Devin Teske <dteske at FreeBSD.org>
 \ All rights reserved.
 \ 
 \ Redistribution and use in source and binary forms, with or without
@@ -24,7 +24,7 @@
 \ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 \ SUCH DAMAGE.
 \ 
-\ $FreeBSD: head/sys/boot/forth/beastie.4th 222417 2011-05-28 08:50:38Z julian $
+\ $FreeBSD: head/sys/boot/forth/beastie.4th 238431 2012-07-14 01:45:35Z dteske $
 
 marker task-beastie.4th
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/forth/beastie.4th.8
--- a/head/sys/boot/forth/beastie.4th.8	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/forth/beastie.4th.8	Wed Jul 25 16:45:04 2012 +0300
@@ -22,14 +22,14 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/sys/boot/forth/beastie.4th.8 222417 2011-05-28 08:50:38Z julian $
+.\" $FreeBSD: head/sys/boot/forth/beastie.4th.8 238431 2012-07-14 01:45:35Z dteske $
 .\"
 .Dd May 16, 2011
 .Dt BEASTIE.4TH 8
 .Os
 .Sh NAME
 .Nm beastie.4th
-.Nd FreeBSD ASCII art boot module.
+.Nd FreeBSD ASCII art boot module
 .Sh DESCRIPTION
 The file that goes by the name of
 .Nm
@@ -168,4 +168,4 @@
 .An Scott Long Aq scottl at FreeBSD.org ,
 .An Aleksander Fafula Aq alex at fafula.com
 and
-.An Devin Teske Aq devinteske at hotmail.com .
+.An Devin Teske Aq dteske at FreeBSD.org .
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/forth/brand.4th
--- a/head/sys/boot/forth/brand.4th	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/forth/brand.4th	Wed Jul 25 16:45:04 2012 +0300
@@ -1,4 +1,4 @@
-\ Copyright (c) 2006-2011 Devin Teske <devinteske at hotmail.com>
+\ Copyright (c) 2006-2011 Devin Teske <dteske at FreeBSD.org>
 \ All rights reserved.
 \ 
 \ Redistribution and use in source and binary forms, with or without
@@ -22,7 +22,7 @@
 \ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 \ SUCH DAMAGE.
 \ 
-\ $FreeBSD: head/sys/boot/forth/brand.4th 222417 2011-05-28 08:50:38Z julian $
+\ $FreeBSD: head/sys/boot/forth/brand.4th 238431 2012-07-14 01:45:35Z dteske $
 
 marker task-brand.4th
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/forth/brand.4th.8
--- a/head/sys/boot/forth/brand.4th.8	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/forth/brand.4th.8	Wed Jul 25 16:45:04 2012 +0300
@@ -22,14 +22,14 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/sys/boot/forth/brand.4th.8 222417 2011-05-28 08:50:38Z julian $
+.\" $FreeBSD: head/sys/boot/forth/brand.4th.8 238431 2012-07-14 01:45:35Z dteske $
 .\"
 .Dd May 18, 2011
 .Dt BRAND.4TH 8
 .Os
 .Sh NAME
 .Nm brand.4th
-.Nd FreeBSD ASCII art boot module.
+.Nd FreeBSD ASCII art boot module
 .Sh DESCRIPTION
 The file that goes by the name of
 .Nm
@@ -122,4 +122,4 @@
 .Nm
 set of commands was written by
 .An -nosplit
-.An Devin Teske Aq devinteske at hotmail.com .
+.An Devin Teske Aq dteske at FreeBSD.org .
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/forth/check-password.4th
--- a/head/sys/boot/forth/check-password.4th	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/forth/check-password.4th	Wed Jul 25 16:45:04 2012 +0300
@@ -1,4 +1,4 @@
-\ Copyright (c) 2006-2011 Devin Teske <devinteske at hotmail.com>
+\ Copyright (c) 2006-2011 Devin Teske <dteske at FreeBSD.org>
 \ All rights reserved.
 \ 
 \ Redistribution and use in source and binary forms, with or without
@@ -22,7 +22,7 @@
 \ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 \ SUCH DAMAGE.
 \ 
-\ $FreeBSD: head/sys/boot/forth/check-password.4th 222417 2011-05-28 08:50:38Z julian $
+\ $FreeBSD: head/sys/boot/forth/check-password.4th 238431 2012-07-14 01:45:35Z dteske $
 
 marker task-check-password.4th
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/forth/check-password.4th.8
--- a/head/sys/boot/forth/check-password.4th.8	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/forth/check-password.4th.8	Wed Jul 25 16:45:04 2012 +0300
@@ -22,14 +22,14 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/sys/boot/forth/check-password.4th.8 222599 2011-06-02 09:56:42Z uqs $
+.\" $FreeBSD: head/sys/boot/forth/check-password.4th.8 238431 2012-07-14 01:45:35Z dteske $
 .\"
 .Dd May 18, 2011
 .Dt CHECK-PASSWORD.4TH 8
 .Os
 .Sh NAME
 .Nm check-password.4th
-.Nd FreeBSD password-checking boot module.
+.Nd FreeBSD password-checking boot module
 .Sh DESCRIPTION
 The file that goes by the name of
 .Nm
@@ -120,4 +120,4 @@
 .Nm
 set of commands was written by
 .An -nosplit
-.An Devin Teske Aq devinteske at hotmail.com .
+.An Devin Teske Aq dteske at FreeBSD.org .
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/forth/color.4th
--- a/head/sys/boot/forth/color.4th	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/forth/color.4th	Wed Jul 25 16:45:04 2012 +0300
@@ -1,4 +1,4 @@
-\ Copyright (c) 2011 Devin Teske <devinteske at hotmail.com>
+\ Copyright (c) 2011 Devin Teske <dteske at FreeBSD.org>
 \ All rights reserved.
 \ 
 \ Redistribution and use in source and binary forms, with or without
@@ -22,7 +22,7 @@
 \ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 \ SUCH DAMAGE.
 \ 
-\ $FreeBSD: head/sys/boot/forth/color.4th 222417 2011-05-28 08:50:38Z julian $
+\ $FreeBSD: head/sys/boot/forth/color.4th 238431 2012-07-14 01:45:35Z dteske $
 
 marker task-color.4th
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/forth/color.4th.8
--- a/head/sys/boot/forth/color.4th.8	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/forth/color.4th.8	Wed Jul 25 16:45:04 2012 +0300
@@ -22,14 +22,14 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/sys/boot/forth/color.4th.8 222417 2011-05-28 08:50:38Z julian $
+.\" $FreeBSD: head/sys/boot/forth/color.4th.8 238431 2012-07-14 01:45:35Z dteske $
 .\"
 .Dd May 18, 2011
 .Dt COLOR.4TH 8
 .Os
 .Sh NAME
 .Nm color.4th
-.Nd FreeBSD color-detection boot module.
+.Nd FreeBSD color-detection boot module
 .Sh DESCRIPTION
 The file that goes by the name of
 .Nm
@@ -114,4 +114,4 @@
 .Nm
 set of commands was written by
 .An -nosplit
-.An Devin Teske Aq devinteske at hotmail.com .
+.An Devin Teske Aq dteske at FreeBSD.org .
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/forth/delay.4th
--- a/head/sys/boot/forth/delay.4th	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/forth/delay.4th	Wed Jul 25 16:45:04 2012 +0300
@@ -1,4 +1,4 @@
-\ Copyright (c) 2008-2011 Devin Teske <devinteske at hotmail.com>
+\ Copyright (c) 2008-2011 Devin Teske <dteske at FreeBSD.org>
 \ All rights reserved.
 \ 
 \ Redistribution and use in source and binary forms, with or without
@@ -22,7 +22,7 @@
 \ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 \ SUCH DAMAGE.
 \ 
-\ $FreeBSD: head/sys/boot/forth/delay.4th 222417 2011-05-28 08:50:38Z julian $
+\ $FreeBSD: head/sys/boot/forth/delay.4th 238431 2012-07-14 01:45:35Z dteske $
 
 marker task-delay.4th
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/forth/delay.4th.8
--- a/head/sys/boot/forth/delay.4th.8	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/forth/delay.4th.8	Wed Jul 25 16:45:04 2012 +0300
@@ -22,14 +22,14 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/sys/boot/forth/delay.4th.8 222417 2011-05-28 08:50:38Z julian $
+.\" $FreeBSD: head/sys/boot/forth/delay.4th.8 238431 2012-07-14 01:45:35Z dteske $
 .\"
 .Dd May 18, 2011
 .Dt DELAY.4TH 8
 .Os
 .Sh NAME
 .Nm delay.4th
-.Nd FreeBSD debugging boot module.
+.Nd FreeBSD debugging boot module
 .Sh DESCRIPTION
 The file that goes by the name of
 .Nm
@@ -123,4 +123,4 @@
 .Nm
 set of commands was written by
 .An -nosplit
-.An Devin Teske Aq devinteske at hotmail.com .
+.An Devin Teske Aq dteske at FreeBSD.org .
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/forth/menu-commands.4th
--- a/head/sys/boot/forth/menu-commands.4th	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/forth/menu-commands.4th	Wed Jul 25 16:45:04 2012 +0300
@@ -1,4 +1,4 @@
-\ Copyright (c) 2006-2011 Devin Teske <devinteske at hotmail.com>
+\ Copyright (c) 2006-2011 Devin Teske <dteske at FreeBSD.org>
 \ All rights reserved.
 \ 
 \ Redistribution and use in source and binary forms, with or without
@@ -22,7 +22,7 @@
 \ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 \ SUCH DAMAGE.
 \ 
-\ $FreeBSD: head/sys/boot/forth/menu-commands.4th 233941 2012-04-06 09:36:22Z avg $
+\ $FreeBSD: head/sys/boot/forth/menu-commands.4th 238431 2012-07-14 01:45:35Z dteske $
 
 marker task-menu-commands.4th
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/forth/menu.4th
--- a/head/sys/boot/forth/menu.4th	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/forth/menu.4th	Wed Jul 25 16:45:04 2012 +0300
@@ -1,6 +1,6 @@
 \ Copyright (c) 2003 Scott Long <scottl at freebsd.org>
 \ Copyright (c) 2003 Aleksander Fafula <alex at fafula.com>
-\ Copyright (c) 2006-2011 Devin Teske <devinteske at hotmail.com>
+\ Copyright (c) 2006-2011 Devin Teske <dteske at FreeBSD.org>
 \ All rights reserved.
 \ 
 \ Redistribution and use in source and binary forms, with or without
@@ -24,7 +24,7 @@
 \ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 \ SUCH DAMAGE.
 \ 
-\ $FreeBSD: head/sys/boot/forth/menu.4th 228985 2011-12-30 06:24:59Z pluknet $
+\ $FreeBSD: head/sys/boot/forth/menu.4th 238431 2012-07-14 01:45:35Z dteske $
 
 marker task-menu.4th
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/forth/menu.4th.8
--- a/head/sys/boot/forth/menu.4th.8	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/forth/menu.4th.8	Wed Jul 25 16:45:04 2012 +0300
@@ -22,14 +22,14 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/sys/boot/forth/menu.4th.8 232158 2012-02-25 15:21:43Z gjb $
+.\" $FreeBSD: head/sys/boot/forth/menu.4th.8 238431 2012-07-14 01:45:35Z dteske $
 .\"
 .Dd February 25, 2012
 .Dt MENU.4TH 8
 .Os
 .Sh NAME
 .Nm menu.4th
-.Nd FreeBSD dynamic menu boot module.
+.Nd FreeBSD dynamic menu boot module
 .Sh DESCRIPTION
 The file that goes by the name of
 .Nm
@@ -320,4 +320,4 @@
 .Nm
 set of commands was written by
 .An -nosplit
-.An Devin Teske Aq devinteske at hotmail.com .
+.An Devin Teske Aq dteske at FreeBSD.org .
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/forth/shortcuts.4th
--- a/head/sys/boot/forth/shortcuts.4th	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/forth/shortcuts.4th	Wed Jul 25 16:45:04 2012 +0300
@@ -1,4 +1,4 @@
-\ Copyright (c) 2008-2011 Devin Teske <devinteske at hotmail.com>
+\ Copyright (c) 2008-2011 Devin Teske <dteske at FreeBSD.org>
 \ All rights reserved.
 \ 
 \ Redistribution and use in source and binary forms, with or without
@@ -22,7 +22,7 @@
 \ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 \ SUCH DAMAGE.
 \ 
-\ $FreeBSD: head/sys/boot/forth/shortcuts.4th 222417 2011-05-28 08:50:38Z julian $
+\ $FreeBSD: head/sys/boot/forth/shortcuts.4th 238431 2012-07-14 01:45:35Z dteske $
 
 \ FICL words intended to be used as shortcuts for carrying out common tasks or
 \ producing common results. Generally, words defined here are simply groupings
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/forth/version.4th
--- a/head/sys/boot/forth/version.4th	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/forth/version.4th	Wed Jul 25 16:45:04 2012 +0300
@@ -1,4 +1,4 @@
-\ Copyright (c) 2006-2011 Devin Teske <devinteske at hotmail.com>
+\ Copyright (c) 2006-2011 Devin Teske <dteske at FreeBSD.org>
 \ All rights reserved.
 \ 
 \ Redistribution and use in source and binary forms, with or without
@@ -22,7 +22,7 @@
 \ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 \ SUCH DAMAGE.
 \ 
-\ $FreeBSD: head/sys/boot/forth/version.4th 222417 2011-05-28 08:50:38Z julian $
+\ $FreeBSD: head/sys/boot/forth/version.4th 238431 2012-07-14 01:45:35Z dteske $
 
 marker task-version.4th
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/forth/version.4th.8
--- a/head/sys/boot/forth/version.4th.8	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/forth/version.4th.8	Wed Jul 25 16:45:04 2012 +0300
@@ -22,14 +22,14 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/sys/boot/forth/version.4th.8 222417 2011-05-28 08:50:38Z julian $
+.\" $FreeBSD: head/sys/boot/forth/version.4th.8 238431 2012-07-14 01:45:35Z dteske $
 .\"
 .Dd May 19, 2011
 .Dt VERSION.4TH 8
 .Os
 .Sh NAME
 .Nm version.4th
-.Nd FreeBSD version string boot module.
+.Nd FreeBSD version string boot module
 .Sh DESCRIPTION
 The file that goes by the name of
 .Nm
@@ -123,4 +123,4 @@
 .Nm
 set of commands was written by
 .An -nosplit
-.An Devin Teske Aq devinteske at hotmail.com .
+.An Devin Teske Aq dteske at FreeBSD.org .
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/i386/boot2/boot2.c
--- a/head/sys/boot/i386/boot2/boot2.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/i386/boot2/boot2.c	Wed Jul 25 16:45:04 2012 +0300
@@ -14,7 +14,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/boot/i386/boot2/boot2.c 232754 2012-03-09 23:30:30Z jkim $");
+__FBSDID("$FreeBSD: head/sys/boot/i386/boot2/boot2.c 236405 2012-06-01 15:48:24Z jhb $");
 
 #include <sys/param.h>
 #include <sys/disklabel.h>
@@ -129,8 +129,8 @@
     int init;
 } dsk;
 static char cmd[512], cmddup[512], knamebuf[1024];
-static const char *kname = NULL;
-static uint32_t opts = 0;
+static const char *kname;
+static uint32_t opts;
 static int comspeed = SIOSPD;
 static struct bootinfo bootinfo;
 static uint8_t ioctrl = IO_KEYBOARD;
@@ -138,7 +138,6 @@
 void exit(int);
 static void load(void);
 static int parse(void);
-static int xfsread(ino_t, void *, size_t);
 static int dskread(void *, unsigned, unsigned);
 static void printf(const char *,...);
 static void putchar(int);
@@ -170,7 +169,7 @@
 #include "ufsread.c"
 
 static inline int
-xfsread(ino_t inode, void *buf, size_t nbyte)
+xfsread(ufs_ino_t inode, void *buf, size_t nbyte)
 {
     if ((size_t)fsread(inode, buf, nbyte) != nbyte) {
 	printf("Invalid %s\n", "format");
@@ -222,7 +221,7 @@
 main(void)
 {
     uint8_t autoboot;
-    ino_t ino;
+    ufs_ino_t ino;
     size_t nbyte;
 
     dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base);
@@ -307,7 +306,7 @@
     static Elf32_Phdr ep[2];
     static Elf32_Shdr es[2];
     caddr_t p;
-    ino_t ino;
+    ufs_ino_t ino;
     uint32_t addr;
     int i, j;
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/i386/btx/btx/Makefile
--- a/head/sys/boot/i386/btx/btx/Makefile	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/i386/btx/btx/Makefile	Wed Jul 25 16:45:04 2012 +0300
@@ -1,4 +1,4 @@
-# $FreeBSD: head/sys/boot/i386/btx/btx/Makefile 232263 2012-02-28 18:30:18Z dim $
+# $FreeBSD: head/sys/boot/i386/btx/btx/Makefile 235154 2012-05-09 08:04:29Z avg $
 
 PROG=	btx
 INTERNALPROG=
@@ -12,6 +12,7 @@
 .endif
 
 CFLAGS+=-DBTX_FLAGS=${BOOT_BTX_FLAGS}
+CFLAGS+=-I${.CURDIR}/../../common
 
 .if defined(BTX_SERIAL)
 BOOT_COMCONSOLE_PORT?= 0x3f8
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/i386/btx/btx/btx.S
--- a/head/sys/boot/i386/btx/btx/btx.S	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/i386/btx/btx/btx.S	Wed Jul 25 16:45:04 2012 +0300
@@ -12,9 +12,11 @@
  * warranties of merchantability and fitness for a particular
  * purpose.
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/boot/i386/btx/btx/btx.S 235154 2012-05-09 08:04:29Z avg $
  */
 
+#include <bootargs.h>
+
 /*
  * Memory layout.
  */
@@ -205,7 +207,7 @@
 		movl $MEM_USR,%edx		# User base address
 		movzwl %ss:BDA_MEM,%eax 	# Get free memory
 		shll $0xa,%eax			# To bytes
-		subl $0x1000,%eax		# Less arg space
+		subl $ARGSPACE,%eax		# Less arg space
 		subl %edx,%eax			# Less base
 		movb $SEL_UDATA,%cl		# User data selector
 		pushl %ecx			# Set SS
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/i386/btx/btxldr/Makefile
--- a/head/sys/boot/i386/btx/btxldr/Makefile	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/i386/btx/btxldr/Makefile	Wed Jul 25 16:45:04 2012 +0300
@@ -1,4 +1,4 @@
-# $FreeBSD: head/sys/boot/i386/btx/btxldr/Makefile 232263 2012-02-28 18:30:18Z dim $
+# $FreeBSD: head/sys/boot/i386/btx/btxldr/Makefile 235154 2012-05-09 08:04:29Z avg $
 
 PROG=	btxldr
 INTERNALPROG=
@@ -6,6 +6,7 @@
 SRCS=	btxldr.S
 
 CFLAGS+=-DLOADER_ADDRESS=${LOADER_ADDRESS}
+CFLAGS+=-I${.CURDIR}/../../common
 
 .if defined(BTXLDR_VERBOSE)
 CFLAGS+=-DBTXLDR_VERBOSE
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/i386/btx/btxldr/btxldr.S
--- a/head/sys/boot/i386/btx/btxldr/btxldr.S	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/i386/btx/btxldr/btxldr.S	Wed Jul 25 16:45:04 2012 +0300
@@ -12,9 +12,11 @@
  * warranties of merchantability and fitness for a particular
  * purpose.
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/boot/i386/btx/btxldr/btxldr.S 235154 2012-05-09 08:04:29Z avg $
  */
 
+#include <bootargs.h>
+
 #define	RBX_MUTE	0x10	/* -m */
 #define	OPT_SET(opt)	(1 << (opt))
 
@@ -89,7 +91,7 @@
 		call hexout			#  stack
 		call putstr			#  pointer
 		movl $m_args,%esi		# Format string
-		leal 0x4(%esp,1),%ebx		# First argument
+		leal 0x4(%esp),%ebx		# First argument
 		movl $0x6,%ecx			# Count
 start.1:	movl (%ebx),%eax		# Get argument and
 		addl $0x4,%ebx			#  bump pointer
@@ -97,24 +99,28 @@
 		loop start.1			# Till done
 		call putstr			# End message
 #endif
-		movl $0x48,%ecx 		# Allocate space
-		subl %ecx,%ebp			#  for bootinfo
-		movl 0x18(%esp,1),%esi		# Source: bootinfo
+		movl BA_BOOTINFO+4(%esp),%esi	# Source: bootinfo
 		cmpl $0x0, %esi			# If the bootinfo pointer
 		je start_null_bi		#  is null, don't copy it
+		movl BI_SIZE(%esi),%ecx 	# Allocate space
+		subl %ecx,%ebp			#  for bootinfo
 		movl %ebp,%edi			# Destination
 		rep				# Copy
 		movsb				#  it
-		movl %ebp,0x18(%esp,1)		# Update pointer
+		movl %ebp,BA_BOOTINFO+4(%esp)	# Update pointer
+		movl %edi,%ebp			# Restore base pointer
 #ifdef BTXLDR_VERBOSE
 		movl $m_rel_bi,%esi		# Display
 		movl %ebp,%eax			#  bootinfo
 		call hexout			#  relocation
 		call putstr			#  message
 #endif
-start_null_bi:	movl $0x18,%ecx 		# Allocate space
-		subl %ecx,%ebp			#  for arguments
-		leal 0x4(%esp,1),%esi		# Source
+start_null_bi:	movl $BOOTARGS_SIZE,%ecx 	# Fixed size of arguments
+		testl $KARGS_FLAGS_EXTARG, BA_BOOTFLAGS+4(%esp) # Check for extra data
+		jz start_fixed			# Skip if the flag is not set
+		addl BOOTARGS_SIZE+4(%esp),%ecx	# Add size of variable args
+start_fixed:	subl $ARGOFF,%ebp		# Place args at fixed offset
+		leal 0x4(%esp),%esi		# Source
 		movl %ebp,%edi			# Destination
 		rep				# Copy
 		movsb				#  them
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/i386/btx/lib/Makefile
--- a/head/sys/boot/i386/btx/lib/Makefile	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/i386/btx/lib/Makefile	Wed Jul 25 16:45:04 2012 +0300
@@ -1,9 +1,10 @@
-# $FreeBSD$
+# $FreeBSD: head/sys/boot/i386/btx/lib/Makefile 235154 2012-05-09 08:04:29Z avg $
 
 PROG=	crt0.o
 INTERNALPROG=
 NO_MAN=
-SRCS=	btxcsu.s btxsys.s btxv86.s
+SRCS=	btxcsu.S btxsys.s btxv86.s
+CFLAGS+=-I${.CURDIR}/../../common
 LDFLAGS=-Wl,-r
 
 .include <bsd.prog.mk>
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/i386/btx/lib/btxcsu.S
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/boot/i386/btx/lib/btxcsu.S	Wed Jul 25 16:45:04 2012 +0300
@@ -0,0 +1,49 @@
+#
+# Copyright (c) 1998 Robert Nordier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are freely
+# permitted provided that the above copyright notice and this
+# paragraph and the following disclaimer are duplicated in all
+# such forms.
+#
+# This software is provided "AS IS" and without any express or
+# implied warranties, including, without limitation, the implied
+# warranties of merchantability and fitness for a particular
+# purpose.
+#
+
+# $FreeBSD: head/sys/boot/i386/btx/lib/btxcsu.S 235154 2012-05-09 08:04:29Z avg $
+
+#include <bootargs.h>
+
+#
+# BTX C startup code (ELF).
+#
+
+#
+# Globals.
+#
+		.global _start
+#
+# Client entry point.
+#
+_start: 	cld
+		pushl %eax
+		movl $_edata,%edi 
+		movl $_end,%ecx 
+		subl %edi, %ecx
+		xorb %al, %al
+		rep
+		stosb
+		popl __base
+		movl %esp,%eax			# Set
+		addl $ARGADJ,%eax		#  argument
+		movl %eax,__args		#  pointer
+		call main			# Invoke client main()
+		call exit			# Invoke client exit()
+#
+# Data.
+#
+		.comm __base,4			# Client base address
+		.comm __args,4			# Client arguments
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/i386/btx/lib/btxcsu.s
--- a/head/sys/boot/i386/btx/lib/btxcsu.s	Wed Jul 25 16:42:35 2012 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-#
-# Copyright (c) 1998 Robert Nordier
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms are freely
-# permitted provided that the above copyright notice and this
-# paragraph and the following disclaimer are duplicated in all
-# such forms.
-#
-# This software is provided "AS IS" and without any express or
-# implied warranties, including, without limitation, the implied
-# warranties of merchantability and fitness for a particular
-# purpose.
-#
-
-# $FreeBSD$
-
-#
-# BTX C startup code (ELF).
-#
-
-#
-# Globals.
-#
-		.global _start
-#
-# Constants.
-#
-		.set ARGADJ,0xfa0		# Argument adjustment
-#
-# Client entry point.
-#
-_start: 	cld
-		pushl %eax
-		movl $_edata,%edi 
-		movl $_end,%ecx 
-		subl %edi, %ecx
-		xorb %al, %al
-		rep
-		stosb
-		popl __base
-		movl %esp,%eax			# Set
-		addl $ARGADJ,%eax		#  argument
-		movl %eax,__args		#  pointer
-		call main			# Invoke client main()
-		call exit			# Invoke client exit()
-#
-# Data.
-#
-		.comm __base,4			# Client base address
-		.comm __args,4			# Client arguments
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/i386/cdboot/Makefile
--- a/head/sys/boot/i386/cdboot/Makefile	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/i386/cdboot/Makefile	Wed Jul 25 16:45:04 2012 +0300
@@ -1,13 +1,19 @@
-# $FreeBSD$
+# $FreeBSD: head/sys/boot/i386/cdboot/Makefile 235281 2012-05-11 18:07:23Z dim $
 
 PROG=	cdboot
 STRIP=
 BINMODE=${NOBINMODE}
 NO_MAN=
-SRCS=	${PROG}.s
+SRCS=	${PROG}.S
+
+CFLAGS+=-I${.CURDIR}/../common
 
 ORG=	0x7c00
 
 LDFLAGS=-e start -Ttext ${ORG} -Wl,-N,-S,--oformat,binary
 
 .include <bsd.prog.mk>
+
+# XXX: clang integrated-as doesn't grok .codeNN directives yet
+CFLAGS.cdboot.S=	${CLANG_NO_IAS}
+CFLAGS+=		${CFLAGS.${.IMPSRC:T}}
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/i386/cdboot/cdboot.S
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/boot/i386/cdboot/cdboot.S	Wed Jul 25 16:45:04 2012 +0300
@@ -0,0 +1,597 @@
+#
+# Copyright (c) 2001 John Baldwin <jhb at FreeBSD.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the author nor the names of any co-contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+# $FreeBSD: head/sys/boot/i386/cdboot/cdboot.S 235219 2012-05-10 09:47:04Z avg $
+
+#
+# This program is a freestanding boot program to load an a.out binary
+# from a CD-ROM booted with no emulation mode as described by the El
+# Torito standard.  Due to broken BIOSen that do not load the desired
+# number of sectors, we try to fit this in as small a space as possible.
+#
+# Basically, we first create a set of boot arguments to pass to the loaded
+# binary.  Then we attempt to load /boot/loader from the CD we were booted
+# off of. 
+#
+
+#include <bootargs.h>
+
+#
+# Memory locations.
+#
+		.set MEM_PAGE_SIZE,0x1000	# memory page size, 4k
+		.set MEM_ARG,0x900		# Arguments at start
+		.set MEM_ARG_BTX,0xa100		# Where we move them to so the
+						#  BTX client can see them
+		.set MEM_ARG_SIZE,0x18		# Size of the arguments
+		.set MEM_BTX_ADDRESS,0x9000	# where BTX lives
+		.set MEM_BTX_ENTRY,0x9010	# where BTX starts to execute
+		.set MEM_BTX_OFFSET,MEM_PAGE_SIZE # offset of BTX in the loader
+		.set MEM_BTX_CLIENT,0xa000	# where BTX clients live
+#
+# a.out header fields
+#
+		.set AOUT_TEXT,0x04		# text segment size
+		.set AOUT_DATA,0x08		# data segment size
+		.set AOUT_BSS,0x0c		# zero'd BSS size
+		.set AOUT_SYMBOLS,0x10		# symbol table
+		.set AOUT_ENTRY,0x14		# entry point
+		.set AOUT_HEADER,MEM_PAGE_SIZE	# size of the a.out header
+#
+# Segment selectors.
+#
+		.set SEL_SDATA,0x8		# Supervisor data
+		.set SEL_RDATA,0x10		# Real mode data
+		.set SEL_SCODE,0x18		# PM-32 code
+		.set SEL_SCODE16,0x20		# PM-16 code
+#
+# BTX constants
+#
+		.set INT_SYS,0x30		# BTX syscall interrupt
+#
+# Constants for reading from the CD.
+#
+		.set ERROR_TIMEOUT,0x80		# BIOS timeout on read
+		.set NUM_RETRIES,3		# Num times to retry
+		.set SECTOR_SIZE,0x800		# size of a sector
+		.set SECTOR_SHIFT,11		# number of place to shift
+		.set BUFFER_LEN,0x100		# number of sectors in buffer
+		.set MAX_READ,0x10000		# max we can read at a time
+		.set MAX_READ_SEC,MAX_READ >> SECTOR_SHIFT
+		.set MEM_READ_BUFFER,0x9000	# buffer to read from CD
+		.set MEM_VOLDESC,MEM_READ_BUFFER # volume descriptor
+		.set MEM_DIR,MEM_VOLDESC+SECTOR_SIZE # Lookup buffer
+		.set VOLDESC_LBA,0x10		# LBA of vol descriptor
+		.set VD_PRIMARY,1		# Primary VD
+		.set VD_END,255			# VD Terminator
+		.set VD_ROOTDIR,156		# Offset of Root Dir Record
+		.set DIR_LEN,0			# Offset of Dir Record length
+		.set DIR_EA_LEN,1		# Offset of EA length
+		.set DIR_EXTENT,2		# Offset of 64-bit LBA
+		.set DIR_SIZE,10		# Offset of 64-bit length
+		.set DIR_NAMELEN,32		# Offset of 8-bit name len
+		.set DIR_NAME,33		# Offset of dir name
+#
+# We expect to be loaded by the BIOS at 0x7c00 (standard boot loader entry
+# point)
+#
+		.code16
+		.globl start
+		.org 0x0, 0x0
+#
+# Program start.
+#
+start:		cld				# string ops inc
+		xor %ax,%ax			# zero %ax
+		mov %ax,%ss			# setup the
+		mov $start,%sp			#  stack
+		mov %ax,%ds			# setup the
+		mov %ax,%es			#  data segments
+		mov %dl,drive			# Save BIOS boot device
+		mov $msg_welcome,%si		# %ds:(%si) -> welcome message
+		call putstr			# display the welcome message
+#
+# Setup the arguments that the loader is expecting from boot[12]
+#
+		mov $msg_bootinfo,%si		# %ds:(%si) -> boot args message
+		call putstr			# display the message
+		mov $MEM_ARG,%bx		# %ds:(%bx) -> boot args
+		mov %bx,%di			# %es:(%di) -> boot args
+		xor %eax,%eax			# zero %eax
+		mov $(MEM_ARG_SIZE/4),%cx	# Size of arguments in 32-bit
+						#  dwords
+		rep				# Clear the arguments
+		stosl				#  to zero
+		mov drive,%dl			# Store BIOS boot device
+		mov %dl,0x4(%bx)		#  in kargs->bootdev
+		or $KARGS_FLAGS_CD,0x8(%bx)	# kargs->bootflags |=
+						#  KARGS_FLAGS_CD
+#
+# Load Volume Descriptor
+#
+		mov $VOLDESC_LBA,%eax		# Set LBA of first VD
+load_vd:	push %eax			# Save %eax
+		mov $1,%dh			# One sector
+		mov $MEM_VOLDESC,%ebx		# Destination
+		call read			# Read it in
+		cmpb $VD_PRIMARY,(%bx)		# Primary VD?
+		je have_vd			# Yes
+		pop %eax			# Prepare to
+		inc %eax			#  try next
+		cmpb $VD_END,(%bx)		# Last VD?
+		jne load_vd			# No, read next
+		mov $msg_novd,%si		# No VD
+		jmp error			# Halt
+have_vd:					# Have Primary VD
+#
+# Try to look up the loader binary using the paths in the loader_paths
+# array.
+#
+		mov $loader_paths,%si		# Point to start of array
+lookup_path:	push %si			# Save file name pointer
+		call lookup			# Try to find file
+		pop %di				# Restore file name pointer
+		jnc lookup_found		# Found this file
+		xor %al,%al			# Look for next
+		mov $0xffff,%cx			#  path name by
+		repnz				#  scanning for
+		scasb				#  nul char
+		mov %di,%si			# Point %si at next path
+		mov (%si),%al			# Get first char of next path
+		or %al,%al			# Is it double nul?
+		jnz lookup_path			# No, try it.
+		mov $msg_failed,%si		# Failed message
+		jmp error			# Halt
+lookup_found:					# Found a loader file
+#
+# Load the binary into the buffer.  Due to real mode addressing limitations
+# we have to read it in 64k chunks.
+#
+		mov DIR_SIZE(%bx),%eax		# Read file length
+		add $SECTOR_SIZE-1,%eax		# Convert length to sectors
+		shr $SECTOR_SHIFT,%eax
+		cmp $BUFFER_LEN,%eax
+		jbe load_sizeok
+		mov $msg_load2big,%si		# Error message
+		call error
+load_sizeok:	movzbw %al,%cx			# Num sectors to read
+		mov DIR_EXTENT(%bx),%eax	# Load extent
+		xor %edx,%edx
+		mov DIR_EA_LEN(%bx),%dl
+		add %edx,%eax			# Skip extended
+		mov $MEM_READ_BUFFER,%ebx	# Read into the buffer
+load_loop:	mov %cl,%dh
+		cmp $MAX_READ_SEC,%cl		# Truncate to max read size
+		jbe load_notrunc
+		mov $MAX_READ_SEC,%dh
+load_notrunc:	sub %dh,%cl			# Update count
+		push %eax			# Save
+		call read			# Read it in
+		pop %eax			# Restore
+		add $MAX_READ_SEC,%eax		# Update LBA
+		add $MAX_READ,%ebx		# Update dest addr
+		jcxz load_done			# Done?
+		jmp load_loop			# Keep going
+load_done:
+#
+# Turn on the A20 address line
+#
+		call seta20			# Turn A20 on
+#
+# Relocate the loader and BTX using a very lazy protected mode
+#
+		mov $msg_relocate,%si		# Display the
+		call putstr			#  relocation message
+		mov MEM_READ_BUFFER+AOUT_ENTRY,%edi # %edi is the destination
+		mov $(MEM_READ_BUFFER+AOUT_HEADER),%esi	# %esi is
+						#  the start of the text
+						#  segment
+		mov MEM_READ_BUFFER+AOUT_TEXT,%ecx # %ecx = length of the text
+						#  segment
+		push %edi			# Save entry point for later
+		lgdt gdtdesc			# setup our own gdt
+		cli				# turn off interrupts
+		mov %cr0,%eax			# Turn on
+		or $0x1,%al			#  protected
+		mov %eax,%cr0			#  mode
+		ljmp $SEL_SCODE,$pm_start	# long jump to clear the
+						#  instruction pre-fetch queue
+		.code32
+pm_start:	mov $SEL_SDATA,%ax		# Initialize
+		mov %ax,%ds			#  %ds and
+		mov %ax,%es			#  %es to a flat selector
+		rep				# Relocate the
+		movsb				#  text segment
+		add $(MEM_PAGE_SIZE - 1),%edi	# pad %edi out to a new page
+		and $~(MEM_PAGE_SIZE - 1),%edi #  for the data segment
+		mov MEM_READ_BUFFER+AOUT_DATA,%ecx # size of the data segment
+		rep				# Relocate the
+		movsb				#  data segment
+		mov MEM_READ_BUFFER+AOUT_BSS,%ecx # size of the bss
+		xor %eax,%eax			# zero %eax
+		add $3,%cl			# round %ecx up to
+		shr $2,%ecx			#  a multiple of 4
+		rep				# zero the
+		stosl				#  bss
+		mov MEM_READ_BUFFER+AOUT_ENTRY,%esi # %esi -> relocated loader
+		add $MEM_BTX_OFFSET,%esi	# %esi -> BTX in the loader
+		mov $MEM_BTX_ADDRESS,%edi	# %edi -> where BTX needs to go
+		movzwl 0xa(%esi),%ecx		# %ecx -> length of BTX
+		rep				# Relocate
+		movsb				#  BTX
+		ljmp $SEL_SCODE16,$pm_16	# Jump to 16-bit PM
+		.code16
+pm_16:		mov $SEL_RDATA,%ax		# Initialize
+		mov %ax,%ds			#  %ds and
+		mov %ax,%es			#  %es to a real mode selector
+		mov %cr0,%eax			# Turn off
+		and $~0x1,%al			#  protected
+		mov %eax,%cr0			#  mode
+		ljmp $0,$pm_end			# Long jump to clear the
+						#  instruction pre-fetch queue
+pm_end:		sti				# Turn interrupts back on now
+#
+# Copy the BTX client to MEM_BTX_CLIENT
+#
+		xor %ax,%ax			# zero %ax and set
+		mov %ax,%ds			#  %ds and %es
+		mov %ax,%es			#  to segment 0
+		mov $MEM_BTX_CLIENT,%di		# Prepare to relocate
+		mov $btx_client,%si		#  the simple btx client
+		mov $(btx_client_end-btx_client),%cx # length of btx client
+		rep				# Relocate the
+		movsb				#  simple BTX client
+#
+# Copy the boot[12] args to where the BTX client can see them
+#
+		mov $MEM_ARG,%si		# where the args are at now
+		mov $MEM_ARG_BTX,%di		# where the args are moving to
+		mov $(MEM_ARG_SIZE/4),%cx	# size of the arguments in longs
+		rep				# Relocate
+		movsl				#  the words
+#
+# Save the entry point so the client can get to it later on
+#
+		pop %eax			# Restore saved entry point
+		stosl				#  and add it to the end of
+						#  the arguments
+#
+# Now we just start up BTX and let it do the rest
+#
+		mov $msg_jump,%si		# Display the
+		call putstr			#  jump message
+		ljmp $0,$MEM_BTX_ENTRY		# Jump to the BTX entry point
+
+#
+# Lookup the file in the path at [SI] from the root directory.
+#
+# Trashes: All but BX
+# Returns: CF = 0 (success), BX = pointer to record
+#          CF = 1 (not found)
+#
+lookup:		mov $VD_ROOTDIR+MEM_VOLDESC,%bx	# Root directory record
+		push %si
+		mov $msg_lookup,%si		# Display lookup message
+		call putstr
+		pop %si
+		push %si
+		call putstr
+		mov $msg_lookup2,%si
+		call putstr
+		pop %si
+lookup_dir:	lodsb				# Get first char of path
+		cmp $0,%al			# Are we done?
+		je lookup_done			# Yes
+		cmp $'/',%al			# Skip path separator.
+		je lookup_dir
+		dec %si				# Undo lodsb side effect
+		call find_file			# Lookup first path item
+		jnc lookup_dir			# Try next component
+		mov $msg_lookupfail,%si		# Not found message
+		call putstr
+		stc				# Set carry
+		ret
+		jmp error
+lookup_done:	mov $msg_lookupok,%si		# Success message
+		call putstr
+		clc				# Clear carry
+		ret
+
+#
+# Lookup file at [SI] in directory whose record is at [BX].
+#
+# Trashes: All but returns
+# Returns: CF = 0 (success), BX = pointer to record, SI = next path item
+#          CF = 1 (not found), SI = preserved
+#
+find_file:	mov DIR_EXTENT(%bx),%eax	# Load extent
+		xor %edx,%edx
+		mov DIR_EA_LEN(%bx),%dl
+		add %edx,%eax			# Skip extended attributes
+		mov %eax,rec_lba		# Save LBA
+		mov DIR_SIZE(%bx),%eax		# Save size
+		mov %eax,rec_size
+		xor %cl,%cl			# Zero length
+		push %si			# Save
+ff.namelen:	inc %cl				# Update length
+		lodsb				# Read char
+		cmp $0,%al			# Nul?
+		je ff.namedone			# Yes
+		cmp $'/',%al			# Path separator?
+		jnz ff.namelen			# No, keep going
+ff.namedone:	dec %cl				# Adjust length and save
+		mov %cl,name_len
+		pop %si				# Restore
+ff.load:	mov rec_lba,%eax		# Load LBA
+		mov $MEM_DIR,%ebx		# Address buffer
+		mov $1,%dh			# One sector
+		call read			# Read directory block
+		incl rec_lba			# Update LBA to next block
+ff.scan:	mov %ebx,%edx			# Check for EOF
+		sub $MEM_DIR,%edx
+		cmp %edx,rec_size
+		ja ff.scan.1
+		stc				# EOF reached
+		ret
+ff.scan.1:	cmpb $0,DIR_LEN(%bx)		# Last record in block?
+		je ff.nextblock
+		push %si			# Save
+		movzbw DIR_NAMELEN(%bx),%si	# Find end of string
+ff.checkver:	cmpb $'0',DIR_NAME-1(%bx,%si)	# Less than '0'?
+		jb ff.checkver.1
+		cmpb $'9',DIR_NAME-1(%bx,%si)	# Greater than '9'?
+		ja ff.checkver.1
+		dec %si				# Next char
+		jnz ff.checkver
+		jmp ff.checklen			# All numbers in name, so
+						#  no version
+ff.checkver.1:	movzbw DIR_NAMELEN(%bx),%cx
+		cmp %cx,%si			# Did we find any digits?
+		je ff.checkdot			# No
+		cmpb $';',DIR_NAME-1(%bx,%si)	# Check for semicolon
+		jne ff.checkver.2
+		dec %si				# Skip semicolon
+		mov %si,%cx
+		mov %cl,DIR_NAMELEN(%bx)	# Adjust length
+		jmp ff.checkdot
+ff.checkver.2:	mov %cx,%si			# Restore %si to end of string
+ff.checkdot:	cmpb $'.',DIR_NAME-1(%bx,%si)	# Trailing dot?
+		jne ff.checklen			# No
+		decb DIR_NAMELEN(%bx)		# Adjust length
+ff.checklen:	pop %si				# Restore
+		movzbw name_len,%cx		# Load length of name
+		cmp %cl,DIR_NAMELEN(%bx)	# Does length match?
+		je ff.checkname			# Yes, check name
+ff.nextrec:	add DIR_LEN(%bx),%bl		# Next record
+		adc $0,%bh
+		jmp ff.scan
+ff.nextblock:	subl $SECTOR_SIZE,rec_size	# Adjust size
+		jnc ff.load			# If subtract ok, keep going
+		ret				# End of file, so not found
+ff.checkname:	lea DIR_NAME(%bx),%di		# Address name in record
+		push %si			# Save
+		repe cmpsb			# Compare name
+		je ff.match			# We have a winner!
+		pop %si				# Restore
+		jmp ff.nextrec			# Keep looking.
+ff.match:	add $2,%sp			# Discard saved %si
+		clc				# Clear carry
+		ret
+
+#
+# Load DH sectors starting at LBA EAX into [EBX].
+#
+# Trashes: EAX
+#
+read:		push %si			# Save
+		push %cx			# Save since some BIOSs trash
+		mov %eax,edd_lba		# LBA to read from
+		mov %ebx,%eax			# Convert address
+		shr $4,%eax			#  to segment
+		mov %ax,edd_addr+0x2		#  and store
+read.retry:	call twiddle			# Entertain the user
+		push %dx			# Save
+		mov $edd_packet,%si		# Address Packet
+		mov %dh,edd_len			# Set length
+		mov drive,%dl			# BIOS Device
+		mov $0x42,%ah			# BIOS: Extended Read
+		int $0x13			# Call BIOS
+		pop %dx				# Restore
+		jc read.fail			# Worked?
+		pop %cx				# Restore
+		pop %si
+		ret				# Return
+read.fail:	cmp $ERROR_TIMEOUT,%ah		# Timeout?
+		je read.retry			# Yes, Retry.
+read.error:	mov %ah,%al			# Save error
+		mov $hex_error,%di		# Format it
+		call hex8			#  as hex
+		mov $msg_badread,%si		# Display Read error message
+
+#
+# Display error message at [SI] and halt.
+#
+error:		call putstr			# Display message
+halt:		hlt
+		jmp halt			# Spin
+
+#
+# Display a null-terminated string.
+#
+# Trashes: AX, SI
+#
+putstr:		push %bx			# Save
+putstr.load:	lodsb				# load %al from %ds:(%si)
+		test %al,%al			# stop at null
+		jnz putstr.putc			# if the char != null, output it
+		pop %bx				# Restore
+		ret				# return when null is hit
+putstr.putc:	call putc			# output char
+		jmp putstr.load			# next char
+
+#
+# Display a single char.
+#
+putc:		mov $0x7,%bx			# attribute for output
+		mov $0xe,%ah			# BIOS: put_char
+		int $0x10			# call BIOS, print char in %al
+		ret				# Return to caller
+
+#
+# Output the "twiddle"
+#
+twiddle:	push %ax			# Save
+		push %bx			# Save
+		mov twiddle_index,%al		# Load index
+		mov $twiddle_chars,%bx		# Address table
+		inc %al				# Next
+		and $3,%al			#  char
+		mov %al,twiddle_index		# Save index for next call
+		xlat				# Get char
+		call putc			# Output it
+		mov $8,%al			# Backspace
+		call putc			# Output it
+		pop %bx				# Restore
+		pop %ax				# Restore
+		ret
+
+#
+# Enable A20. Put an upper limit on the amount of time we wait for the
+# keyboard controller to get ready (65K x ISA access time). If
+# we wait more than that amount, the hardware is probably
+# legacy-free and simply doesn't have a keyboard controller.
+# Thus, the A20 line is already enabled.
+#
+seta20: 	cli				# Disable interrupts
+		xor %cx,%cx			# Clear
+seta20.1:	inc %cx				# Increment, overflow?
+		jz seta20.3			# Yes
+		in $0x64,%al			# Get status
+		test $0x2,%al			# Busy?
+		jnz seta20.1			# Yes
+		mov $0xd1,%al			# Command: Write
+		out %al,$0x64			#  output port
+seta20.2:	in $0x64,%al			# Get status
+		test $0x2,%al			# Busy?
+		jnz seta20.2			# Yes
+		mov $0xdf,%al			# Enable
+		out %al,$0x60			#  A20
+seta20.3:	sti				# Enable interrupts
+		ret				# To caller
+
+#
+# Convert AL to hex, saving the result to [EDI].
+#
+hex8:		pushl %eax			# Save
+		shrb $0x4,%al			# Do upper
+		call hex8.1			#  4
+		popl %eax			# Restore
+hex8.1: 	andb $0xf,%al			# Get lower 4
+		cmpb $0xa,%al			# Convert
+		sbbb $0x69,%al			#  to hex
+		das				#  digit
+		orb $0x20,%al			# To lower case
+		stosb				# Save char
+		ret				# (Recursive)
+
+#
+# BTX client to start btxldr
+#
+		.code32
+btx_client:	mov $(MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE-4), %esi
+						# %ds:(%esi) -> end
+						#  of boot[12] args
+		mov $(MEM_ARG_SIZE/4),%ecx	# Number of words to push
+		std				# Go backwards
+push_arg:	lodsl				# Read argument
+		push %eax			# Push it onto the stack
+		loop push_arg			# Push all of the arguments
+		cld				# In case anyone depends on this
+		pushl MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE # Entry point of
+						#  the loader
+		push %eax			# Emulate a near call
+		mov $0x1,%eax			# 'exec' system call
+		int $INT_SYS			# BTX system call
+btx_client_end:
+		.code16
+
+		.p2align 4
+#
+# Global descriptor table.
+#
+gdt:		.word 0x0,0x0,0x0,0x0		# Null entry
+		.word 0xffff,0x0,0x9200,0xcf	# SEL_SDATA
+		.word 0xffff,0x0,0x9200,0x0	# SEL_RDATA
+		.word 0xffff,0x0,0x9a00,0xcf	# SEL_SCODE (32-bit)
+		.word 0xffff,0x0,0x9a00,0x8f	# SEL_SCODE16 (16-bit)
+gdt.1:
+#
+# Pseudo-descriptors.
+#
+gdtdesc:	.word gdt.1-gdt-1		# Limit
+		.long gdt			# Base
+#
+# EDD Packet
+#
+edd_packet:	.byte 0x10			# Length
+		.byte 0				# Reserved
+edd_len:	.byte 0x0			# Num to read
+		.byte 0				# Reserved
+edd_addr:	.word 0x0,0x0			# Seg:Off
+edd_lba:	.quad 0x0			# LBA
+
+drive:		.byte 0
+
+#
+# State for searching dir
+#
+rec_lba:	.long 0x0			# LBA (adjusted for EA)
+rec_size:	.long 0x0			# File size
+name_len:	.byte 0x0			# Length of current name
+
+twiddle_index:	.byte 0x0
+
+msg_welcome:	.asciz	"CD Loader 1.2\r\n\n"
+msg_bootinfo:	.asciz	"Building the boot loader arguments\r\n"
+msg_relocate:	.asciz	"Relocating the loader and the BTX\r\n"
+msg_jump:	.asciz	"Starting the BTX loader\r\n"
+msg_badread:	.ascii  "Read Error: 0x"
+hex_error:	.asciz	"00\r\n"
+msg_novd:	.asciz  "Could not find Primary Volume Descriptor\r\n"
+msg_lookup:	.asciz  "Looking up "
+msg_lookup2:	.asciz  "... "
+msg_lookupok:	.asciz  "Found\r\n"
+msg_lookupfail:	.asciz  "File not found\r\n"
+msg_load2big:	.asciz  "File too big\r\n"
+msg_failed:	.asciz	"Boot failed\r\n"
+twiddle_chars:	.ascii	"|/-\\"
+loader_paths:	.asciz  "/BOOT/LOADER"
+		.asciz	"/boot/loader"
+		.byte 0
+
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/i386/cdboot/cdboot.s
--- a/head/sys/boot/i386/cdboot/cdboot.s	Wed Jul 25 16:42:35 2012 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,600 +0,0 @@
-#
-# Copyright (c) 2001 John Baldwin <jhb at FreeBSD.org>
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-#    notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-#    notice, this list of conditions and the following disclaimer in the
-#    documentation and/or other materials provided with the distribution.
-# 3. Neither the name of the author nor the names of any co-contributors
-#    may be used to endorse or promote products derived from this software
-#    without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-# SUCH DAMAGE.
-#
-
-# $FreeBSD$
-
-#
-# This program is a freestanding boot program to load an a.out binary
-# from a CD-ROM booted with no emulation mode as described by the El
-# Torito standard.  Due to broken BIOSen that do not load the desired
-# number of sectors, we try to fit this in as small a space as possible.
-#
-# Basically, we first create a set of boot arguments to pass to the loaded
-# binary.  Then we attempt to load /boot/loader from the CD we were booted
-# off of. 
-#
-
-#
-# Memory locations.
-#
-		.set MEM_PAGE_SIZE,0x1000	# memory page size, 4k
-		.set MEM_ARG,0x900		# Arguments at start
-		.set MEM_ARG_BTX,0xa100		# Where we move them to so the
-						#  BTX client can see them
-		.set MEM_ARG_SIZE,0x18		# Size of the arguments
-		.set MEM_BTX_ADDRESS,0x9000	# where BTX lives
-		.set MEM_BTX_ENTRY,0x9010	# where BTX starts to execute
-		.set MEM_BTX_OFFSET,MEM_PAGE_SIZE # offset of BTX in the loader
-		.set MEM_BTX_CLIENT,0xa000	# where BTX clients live
-#
-# a.out header fields
-#
-		.set AOUT_TEXT,0x04		# text segment size
-		.set AOUT_DATA,0x08		# data segment size
-		.set AOUT_BSS,0x0c		# zero'd BSS size
-		.set AOUT_SYMBOLS,0x10		# symbol table
-		.set AOUT_ENTRY,0x14		# entry point
-		.set AOUT_HEADER,MEM_PAGE_SIZE	# size of the a.out header
-#
-# Flags for kargs->bootflags
-#
-		.set KARGS_FLAGS_CD,0x1		# flag to indicate booting from
-						#  CD loader
-#
-# Segment selectors.
-#
-		.set SEL_SDATA,0x8		# Supervisor data
-		.set SEL_RDATA,0x10		# Real mode data
-		.set SEL_SCODE,0x18		# PM-32 code
-		.set SEL_SCODE16,0x20		# PM-16 code
-#
-# BTX constants
-#
-		.set INT_SYS,0x30		# BTX syscall interrupt
-#
-# Constants for reading from the CD.
-#
-		.set ERROR_TIMEOUT,0x80		# BIOS timeout on read
-		.set NUM_RETRIES,3		# Num times to retry
-		.set SECTOR_SIZE,0x800		# size of a sector
-		.set SECTOR_SHIFT,11		# number of place to shift
-		.set BUFFER_LEN,0x100		# number of sectors in buffer
-		.set MAX_READ,0x10000		# max we can read at a time
-		.set MAX_READ_SEC,MAX_READ >> SECTOR_SHIFT
-		.set MEM_READ_BUFFER,0x9000	# buffer to read from CD
-		.set MEM_VOLDESC,MEM_READ_BUFFER # volume descriptor
-		.set MEM_DIR,MEM_VOLDESC+SECTOR_SIZE # Lookup buffer
-		.set VOLDESC_LBA,0x10		# LBA of vol descriptor
-		.set VD_PRIMARY,1		# Primary VD
-		.set VD_END,255			# VD Terminator
-		.set VD_ROOTDIR,156		# Offset of Root Dir Record
-		.set DIR_LEN,0			# Offset of Dir Record length
-		.set DIR_EA_LEN,1		# Offset of EA length
-		.set DIR_EXTENT,2		# Offset of 64-bit LBA
-		.set DIR_SIZE,10		# Offset of 64-bit length
-		.set DIR_NAMELEN,32		# Offset of 8-bit name len
-		.set DIR_NAME,33		# Offset of dir name
-#
-# We expect to be loaded by the BIOS at 0x7c00 (standard boot loader entry
-# point)
-#
-		.code16
-		.globl start
-		.org 0x0, 0x0
-#
-# Program start.
-#
-start:		cld				# string ops inc
-		xor %ax,%ax			# zero %ax
-		mov %ax,%ss			# setup the
-		mov $start,%sp			#  stack
-		mov %ax,%ds			# setup the
-		mov %ax,%es			#  data segments
-		mov %dl,drive			# Save BIOS boot device
-		mov $msg_welcome,%si		# %ds:(%si) -> welcome message
-		call putstr			# display the welcome message
-#
-# Setup the arguments that the loader is expecting from boot[12]
-#
-		mov $msg_bootinfo,%si		# %ds:(%si) -> boot args message
-		call putstr			# display the message
-		mov $MEM_ARG,%bx		# %ds:(%bx) -> boot args
-		mov %bx,%di			# %es:(%di) -> boot args
-		xor %eax,%eax			# zero %eax
-		mov $(MEM_ARG_SIZE/4),%cx	# Size of arguments in 32-bit
-						#  dwords
-		rep				# Clear the arguments
-		stosl				#  to zero
-		mov drive,%dl			# Store BIOS boot device
-		mov %dl,0x4(%bx)		#  in kargs->bootdev
-		or $KARGS_FLAGS_CD,0x8(%bx)	# kargs->bootflags |=
-						#  KARGS_FLAGS_CD
-#
-# Load Volume Descriptor
-#
-		mov $VOLDESC_LBA,%eax		# Set LBA of first VD
-load_vd:	push %eax			# Save %eax
-		mov $1,%dh			# One sector
-		mov $MEM_VOLDESC,%ebx		# Destination
-		call read			# Read it in
-		cmpb $VD_PRIMARY,(%bx)		# Primary VD?
-		je have_vd			# Yes
-		pop %eax			# Prepare to
-		inc %eax			#  try next
-		cmpb $VD_END,(%bx)		# Last VD?
-		jne load_vd			# No, read next
-		mov $msg_novd,%si		# No VD
-		jmp error			# Halt
-have_vd:					# Have Primary VD
-#
-# Try to look up the loader binary using the paths in the loader_paths
-# array.
-#
-		mov $loader_paths,%si		# Point to start of array
-lookup_path:	push %si			# Save file name pointer
-		call lookup			# Try to find file
-		pop %di				# Restore file name pointer
-		jnc lookup_found		# Found this file
-		xor %al,%al			# Look for next
-		mov $0xffff,%cx			#  path name by
-		repnz				#  scanning for
-		scasb				#  nul char
-		mov %di,%si			# Point %si at next path
-		mov (%si),%al			# Get first char of next path
-		or %al,%al			# Is it double nul?
-		jnz lookup_path			# No, try it.
-		mov $msg_failed,%si		# Failed message
-		jmp error			# Halt
-lookup_found:					# Found a loader file
-#
-# Load the binary into the buffer.  Due to real mode addressing limitations
-# we have to read it in 64k chunks.
-#
-		mov DIR_SIZE(%bx),%eax		# Read file length
-		add $SECTOR_SIZE-1,%eax		# Convert length to sectors
-		shr $SECTOR_SHIFT,%eax
-		cmp $BUFFER_LEN,%eax
-		jbe load_sizeok
-		mov $msg_load2big,%si		# Error message
-		call error
-load_sizeok:	movzbw %al,%cx			# Num sectors to read
-		mov DIR_EXTENT(%bx),%eax	# Load extent
-		xor %edx,%edx
-		mov DIR_EA_LEN(%bx),%dl
-		add %edx,%eax			# Skip extended
-		mov $MEM_READ_BUFFER,%ebx	# Read into the buffer
-load_loop:	mov %cl,%dh
-		cmp $MAX_READ_SEC,%cl		# Truncate to max read size
-		jbe load_notrunc
-		mov $MAX_READ_SEC,%dh
-load_notrunc:	sub %dh,%cl			# Update count
-		push %eax			# Save
-		call read			# Read it in
-		pop %eax			# Restore
-		add $MAX_READ_SEC,%eax		# Update LBA
-		add $MAX_READ,%ebx		# Update dest addr
-		jcxz load_done			# Done?
-		jmp load_loop			# Keep going
-load_done:
-#
-# Turn on the A20 address line
-#
-		call seta20			# Turn A20 on
-#
-# Relocate the loader and BTX using a very lazy protected mode
-#
-		mov $msg_relocate,%si		# Display the
-		call putstr			#  relocation message
-		mov MEM_READ_BUFFER+AOUT_ENTRY,%edi # %edi is the destination
-		mov $(MEM_READ_BUFFER+AOUT_HEADER),%esi	# %esi is
-						#  the start of the text
-						#  segment
-		mov MEM_READ_BUFFER+AOUT_TEXT,%ecx # %ecx = length of the text
-						#  segment
-		push %edi			# Save entry point for later
-		lgdt gdtdesc			# setup our own gdt
-		cli				# turn off interrupts
-		mov %cr0,%eax			# Turn on
-		or $0x1,%al			#  protected
-		mov %eax,%cr0			#  mode
-		ljmp $SEL_SCODE,$pm_start	# long jump to clear the
-						#  instruction pre-fetch queue
-		.code32
-pm_start:	mov $SEL_SDATA,%ax		# Initialize
-		mov %ax,%ds			#  %ds and
-		mov %ax,%es			#  %es to a flat selector
-		rep				# Relocate the
-		movsb				#  text segment
-		add $(MEM_PAGE_SIZE - 1),%edi	# pad %edi out to a new page
-		and $~(MEM_PAGE_SIZE - 1),%edi #  for the data segment
-		mov MEM_READ_BUFFER+AOUT_DATA,%ecx # size of the data segment
-		rep				# Relocate the
-		movsb				#  data segment
-		mov MEM_READ_BUFFER+AOUT_BSS,%ecx # size of the bss
-		xor %eax,%eax			# zero %eax
-		add $3,%cl			# round %ecx up to
-		shr $2,%ecx			#  a multiple of 4
-		rep				# zero the
-		stosl				#  bss
-		mov MEM_READ_BUFFER+AOUT_ENTRY,%esi # %esi -> relocated loader
-		add $MEM_BTX_OFFSET,%esi	# %esi -> BTX in the loader
-		mov $MEM_BTX_ADDRESS,%edi	# %edi -> where BTX needs to go
-		movzwl 0xa(%esi),%ecx		# %ecx -> length of BTX
-		rep				# Relocate
-		movsb				#  BTX
-		ljmp $SEL_SCODE16,$pm_16	# Jump to 16-bit PM
-		.code16
-pm_16:		mov $SEL_RDATA,%ax		# Initialize
-		mov %ax,%ds			#  %ds and
-		mov %ax,%es			#  %es to a real mode selector
-		mov %cr0,%eax			# Turn off
-		and $~0x1,%al			#  protected
-		mov %eax,%cr0			#  mode
-		ljmp $0,$pm_end			# Long jump to clear the
-						#  instruction pre-fetch queue
-pm_end:		sti				# Turn interrupts back on now
-#
-# Copy the BTX client to MEM_BTX_CLIENT
-#
-		xor %ax,%ax			# zero %ax and set
-		mov %ax,%ds			#  %ds and %es
-		mov %ax,%es			#  to segment 0
-		mov $MEM_BTX_CLIENT,%di		# Prepare to relocate
-		mov $btx_client,%si		#  the simple btx client
-		mov $(btx_client_end-btx_client),%cx # length of btx client
-		rep				# Relocate the
-		movsb				#  simple BTX client
-#
-# Copy the boot[12] args to where the BTX client can see them
-#
-		mov $MEM_ARG,%si		# where the args are at now
-		mov $MEM_ARG_BTX,%di		# where the args are moving to
-		mov $(MEM_ARG_SIZE/4),%cx	# size of the arguments in longs
-		rep				# Relocate
-		movsl				#  the words
-#
-# Save the entry point so the client can get to it later on
-#
-		pop %eax			# Restore saved entry point
-		stosl				#  and add it to the end of
-						#  the arguments
-#
-# Now we just start up BTX and let it do the rest
-#
-		mov $msg_jump,%si		# Display the
-		call putstr			#  jump message
-		ljmp $0,$MEM_BTX_ENTRY		# Jump to the BTX entry point
-
-#
-# Lookup the file in the path at [SI] from the root directory.
-#
-# Trashes: All but BX
-# Returns: CF = 0 (success), BX = pointer to record
-#          CF = 1 (not found)
-#
-lookup:		mov $VD_ROOTDIR+MEM_VOLDESC,%bx	# Root directory record
-		push %si
-		mov $msg_lookup,%si		# Display lookup message
-		call putstr
-		pop %si
-		push %si
-		call putstr
-		mov $msg_lookup2,%si
-		call putstr
-		pop %si
-lookup_dir:	lodsb				# Get first char of path
-		cmp $0,%al			# Are we done?
-		je lookup_done			# Yes
-		cmp $'/',%al			# Skip path separator.
-		je lookup_dir
-		dec %si				# Undo lodsb side effect
-		call find_file			# Lookup first path item
-		jnc lookup_dir			# Try next component
-		mov $msg_lookupfail,%si		# Not found message
-		call putstr
-		stc				# Set carry
-		ret
-		jmp error
-lookup_done:	mov $msg_lookupok,%si		# Success message
-		call putstr
-		clc				# Clear carry
-		ret
-
-#
-# Lookup file at [SI] in directory whose record is at [BX].
-#
-# Trashes: All but returns
-# Returns: CF = 0 (success), BX = pointer to record, SI = next path item
-#          CF = 1 (not found), SI = preserved
-#
-find_file:	mov DIR_EXTENT(%bx),%eax	# Load extent
-		xor %edx,%edx
-		mov DIR_EA_LEN(%bx),%dl
-		add %edx,%eax			# Skip extended attributes
-		mov %eax,rec_lba		# Save LBA
-		mov DIR_SIZE(%bx),%eax		# Save size
-		mov %eax,rec_size
-		xor %cl,%cl			# Zero length
-		push %si			# Save
-ff.namelen:	inc %cl				# Update length
-		lodsb				# Read char
-		cmp $0,%al			# Nul?
-		je ff.namedone			# Yes
-		cmp $'/',%al			# Path separator?
-		jnz ff.namelen			# No, keep going
-ff.namedone:	dec %cl				# Adjust length and save
-		mov %cl,name_len
-		pop %si				# Restore
-ff.load:	mov rec_lba,%eax		# Load LBA
-		mov $MEM_DIR,%ebx		# Address buffer
-		mov $1,%dh			# One sector
-		call read			# Read directory block
-		incl rec_lba			# Update LBA to next block
-ff.scan:	mov %ebx,%edx			# Check for EOF
-		sub $MEM_DIR,%edx
-		cmp %edx,rec_size
-		ja ff.scan.1
-		stc				# EOF reached
-		ret
-ff.scan.1:	cmpb $0,DIR_LEN(%bx)		# Last record in block?
-		je ff.nextblock
-		push %si			# Save
-		movzbw DIR_NAMELEN(%bx),%si	# Find end of string
-ff.checkver:	cmpb $'0',DIR_NAME-1(%bx,%si)	# Less than '0'?
-		jb ff.checkver.1
-		cmpb $'9',DIR_NAME-1(%bx,%si)	# Greater than '9'?
-		ja ff.checkver.1
-		dec %si				# Next char
-		jnz ff.checkver
-		jmp ff.checklen			# All numbers in name, so
-						#  no version
-ff.checkver.1:	movzbw DIR_NAMELEN(%bx),%cx
-		cmp %cx,%si			# Did we find any digits?
-		je ff.checkdot			# No
-		cmpb $';',DIR_NAME-1(%bx,%si)	# Check for semicolon
-		jne ff.checkver.2
-		dec %si				# Skip semicolon
-		mov %si,%cx
-		mov %cl,DIR_NAMELEN(%bx)	# Adjust length
-		jmp ff.checkdot
-ff.checkver.2:	mov %cx,%si			# Restore %si to end of string
-ff.checkdot:	cmpb $'.',DIR_NAME-1(%bx,%si)	# Trailing dot?
-		jne ff.checklen			# No
-		decb DIR_NAMELEN(%bx)		# Adjust length
-ff.checklen:	pop %si				# Restore
-		movzbw name_len,%cx		# Load length of name
-		cmp %cl,DIR_NAMELEN(%bx)	# Does length match?
-		je ff.checkname			# Yes, check name
-ff.nextrec:	add DIR_LEN(%bx),%bl		# Next record
-		adc $0,%bh
-		jmp ff.scan
-ff.nextblock:	subl $SECTOR_SIZE,rec_size	# Adjust size
-		jnc ff.load			# If subtract ok, keep going
-		ret				# End of file, so not found
-ff.checkname:	lea DIR_NAME(%bx),%di		# Address name in record
-		push %si			# Save
-		repe cmpsb			# Compare name
-		je ff.match			# We have a winner!
-		pop %si				# Restore
-		jmp ff.nextrec			# Keep looking.
-ff.match:	add $2,%sp			# Discard saved %si
-		clc				# Clear carry
-		ret
-
-#
-# Load DH sectors starting at LBA EAX into [EBX].
-#
-# Trashes: EAX
-#
-read:		push %si			# Save
-		push %cx			# Save since some BIOSs trash
-		mov %eax,edd_lba		# LBA to read from
-		mov %ebx,%eax			# Convert address
-		shr $4,%eax			#  to segment
-		mov %ax,edd_addr+0x2		#  and store
-read.retry:	call twiddle			# Entertain the user
-		push %dx			# Save
-		mov $edd_packet,%si		# Address Packet
-		mov %dh,edd_len			# Set length
-		mov drive,%dl			# BIOS Device
-		mov $0x42,%ah			# BIOS: Extended Read
-		int $0x13			# Call BIOS
-		pop %dx				# Restore
-		jc read.fail			# Worked?
-		pop %cx				# Restore
-		pop %si
-		ret				# Return
-read.fail:	cmp $ERROR_TIMEOUT,%ah		# Timeout?
-		je read.retry			# Yes, Retry.
-read.error:	mov %ah,%al			# Save error
-		mov $hex_error,%di		# Format it
-		call hex8			#  as hex
-		mov $msg_badread,%si		# Display Read error message
-
-#
-# Display error message at [SI] and halt.
-#
-error:		call putstr			# Display message
-halt:		hlt
-		jmp halt			# Spin
-
-#
-# Display a null-terminated string.
-#
-# Trashes: AX, SI
-#
-putstr:		push %bx			# Save
-putstr.load:	lodsb				# load %al from %ds:(%si)
-		test %al,%al			# stop at null
-		jnz putstr.putc			# if the char != null, output it
-		pop %bx				# Restore
-		ret				# return when null is hit
-putstr.putc:	call putc			# output char
-		jmp putstr.load			# next char
-
-#
-# Display a single char.
-#
-putc:		mov $0x7,%bx			# attribute for output
-		mov $0xe,%ah			# BIOS: put_char
-		int $0x10			# call BIOS, print char in %al
-		ret				# Return to caller
-
-#
-# Output the "twiddle"
-#
-twiddle:	push %ax			# Save
-		push %bx			# Save
-		mov twiddle_index,%al		# Load index
-		mov $twiddle_chars,%bx		# Address table
-		inc %al				# Next
-		and $3,%al			#  char
-		mov %al,twiddle_index		# Save index for next call
-		xlat				# Get char
-		call putc			# Output it
-		mov $8,%al			# Backspace
-		call putc			# Output it
-		pop %bx				# Restore
-		pop %ax				# Restore
-		ret
-
-#
-# Enable A20. Put an upper limit on the amount of time we wait for the
-# keyboard controller to get ready (65K x ISA access time). If
-# we wait more than that amount, the hardware is probably
-# legacy-free and simply doesn't have a keyboard controller.
-# Thus, the A20 line is already enabled.
-#
-seta20: 	cli				# Disable interrupts
-		xor %cx,%cx			# Clear
-seta20.1:	inc %cx				# Increment, overflow?
-		jz seta20.3			# Yes
-		in $0x64,%al			# Get status
-		test $0x2,%al			# Busy?
-		jnz seta20.1			# Yes
-		mov $0xd1,%al			# Command: Write
-		out %al,$0x64			#  output port
-seta20.2:	in $0x64,%al			# Get status
-		test $0x2,%al			# Busy?
-		jnz seta20.2			# Yes
-		mov $0xdf,%al			# Enable
-		out %al,$0x60			#  A20
-seta20.3:	sti				# Enable interrupts
-		ret				# To caller
-
-#
-# Convert AL to hex, saving the result to [EDI].
-#
-hex8:		pushl %eax			# Save
-		shrb $0x4,%al			# Do upper
-		call hex8.1			#  4
-		popl %eax			# Restore
-hex8.1: 	andb $0xf,%al			# Get lower 4
-		cmpb $0xa,%al			# Convert
-		sbbb $0x69,%al			#  to hex
-		das				#  digit
-		orb $0x20,%al			# To lower case
-		stosb				# Save char
-		ret				# (Recursive)
-
-#
-# BTX client to start btxldr
-#
-		.code32
-btx_client:	mov $(MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE-4), %esi
-						# %ds:(%esi) -> end
-						#  of boot[12] args
-		mov $(MEM_ARG_SIZE/4),%ecx	# Number of words to push
-		std				# Go backwards
-push_arg:	lodsl				# Read argument
-		push %eax			# Push it onto the stack
-		loop push_arg			# Push all of the arguments
-		cld				# In case anyone depends on this
-		pushl MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE # Entry point of
-						#  the loader
-		push %eax			# Emulate a near call
-		mov $0x1,%eax			# 'exec' system call
-		int $INT_SYS			# BTX system call
-btx_client_end:
-		.code16
-
-		.p2align 4
-#
-# Global descriptor table.
-#
-gdt:		.word 0x0,0x0,0x0,0x0		# Null entry
-		.word 0xffff,0x0,0x9200,0xcf	# SEL_SDATA
-		.word 0xffff,0x0,0x9200,0x0	# SEL_RDATA
-		.word 0xffff,0x0,0x9a00,0xcf	# SEL_SCODE (32-bit)
-		.word 0xffff,0x0,0x9a00,0x8f	# SEL_SCODE16 (16-bit)
-gdt.1:
-#
-# Pseudo-descriptors.
-#
-gdtdesc:	.word gdt.1-gdt-1		# Limit
-		.long gdt			# Base
-#
-# EDD Packet
-#
-edd_packet:	.byte 0x10			# Length
-		.byte 0				# Reserved
-edd_len:	.byte 0x0			# Num to read
-		.byte 0				# Reserved
-edd_addr:	.word 0x0,0x0			# Seg:Off
-edd_lba:	.quad 0x0			# LBA
-
-drive:		.byte 0
-
-#
-# State for searching dir
-#
-rec_lba:	.long 0x0			# LBA (adjusted for EA)
-rec_size:	.long 0x0			# File size
-name_len:	.byte 0x0			# Length of current name
-
-twiddle_index:	.byte 0x0
-
-msg_welcome:	.asciz	"CD Loader 1.2\r\n\n"
-msg_bootinfo:	.asciz	"Building the boot loader arguments\r\n"
-msg_relocate:	.asciz	"Relocating the loader and the BTX\r\n"
-msg_jump:	.asciz	"Starting the BTX loader\r\n"
-msg_badread:	.ascii  "Read Error: 0x"
-hex_error:	.asciz	"00\r\n"
-msg_novd:	.asciz  "Could not find Primary Volume Descriptor\r\n"
-msg_lookup:	.asciz  "Looking up "
-msg_lookup2:	.asciz  "... "
-msg_lookupok:	.asciz  "Found\r\n"
-msg_lookupfail:	.asciz  "File not found\r\n"
-msg_load2big:	.asciz  "File too big\r\n"
-msg_failed:	.asciz	"Boot failed\r\n"
-twiddle_chars:	.ascii	"|/-\\"
-loader_paths:	.asciz  "/BOOT/LOADER"
-		.asciz	"/boot/loader"
-		.byte 0
-
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/i386/common/bootargs.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/boot/i386/common/bootargs.h	Wed Jul 25 16:45:04 2012 +0300
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 2012 Andriy Gapon <avg at FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ *
+ * $FreeBSD: head/sys/boot/i386/common/bootargs.h 235154 2012-05-09 08:04:29Z avg $
+ */
+
+#ifndef _BOOT_I386_ARGS_H_
+#define	_BOOT_I386_ARGS_H_
+
+#define	KARGS_FLAGS_CD		0x1
+#define	KARGS_FLAGS_PXE		0x2
+#define	KARGS_FLAGS_ZFS		0x4
+#define	KARGS_FLAGS_EXTARG	0x8	/* variably sized extended argument */
+
+#define	BOOTARGS_SIZE	24	/* sizeof(struct bootargs) */
+#define	BA_BOOTFLAGS	8	/* offsetof(struct bootargs, bootflags) */
+#define	BA_BOOTINFO	20	/* offsetof(struct bootargs, bootinfo) */
+#define	BI_SIZE		48	/* offsetof(struct bootinfo, bi_size) */
+
+/*
+ * We reserve some space above BTX allocated stack for the arguments
+ * and certain data that could hang off them.  Currently only struct bootinfo
+ * is supported in that category.  The bootinfo is placed at the top
+ * of the arguments area and the actual arguments are placed at ARGOFF offset
+ * from the top and grow towards the top.  Hopefully we have enough space
+ * for bootinfo and the arguments to not run into each other.
+ * Arguments area below ARGOFF is reserved for future use.
+ */
+#define	ARGSPACE	0x1000	/* total size of the BTX args area */
+#define	ARGOFF		0x800	/* actual args offset within the args area */
+#define	ARGADJ		(ARGSPACE - ARGOFF)
+
+#ifndef __ASSEMBLER__
+
+struct bootargs
+{
+	uint32_t			howto;
+	uint32_t			bootdev;
+	uint32_t			bootflags;
+	union {
+		struct {
+			uint32_t	pxeinfo;
+			uint32_t	reserved;
+		};
+		uint64_t		zfspool;
+	};
+	uint32_t			bootinfo;
+
+	/*
+	 * If KARGS_FLAGS_EXTARG is set in bootflags, then the above fields
+	 * are followed by a uint32_t field that specifies a size of the
+	 * extended arguments (including the size field).
+	 */
+};
+
+#endif /*__ASSEMBLER__*/
+
+#endif	/* !_BOOT_I386_ARGS_H_ */
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/i386/efi/reloc.c
--- a/head/sys/boot/i386/efi/reloc.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/i386/efi/reloc.c	Wed Jul 25 16:45:04 2012 +0300
@@ -25,21 +25,12 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/boot/i386/efi/reloc.c 235153 2012-05-09 07:55:42Z avg $");
 
 #include <sys/types.h>
 #include <sys/elf32.h>
 #include <efi.h>
-
-/*
- * XXX: we can't include sys/systm.h.
- */
-#ifndef CTASSERT                /* Allow lint to override */
-#define CTASSERT(x)             _CTASSERT(x, __LINE__)
-#define _CTASSERT(x, y)         __CTASSERT(x, y)
-#define __CTASSERT(x, y)        typedef char __assert ## y[(x) ? 1 : -1]
-#endif
-
+#include <bootstrap.h>
 
 /*
  * A simple relocator for IA32 EFI binaries.
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/i386/gptboot/gptboot.c
--- a/head/sys/boot/i386/gptboot/gptboot.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/i386/gptboot/gptboot.c	Wed Jul 25 16:45:04 2012 +0300
@@ -14,7 +14,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/boot/i386/gptboot/gptboot.c 226506 2011-10-18 09:46:52Z des $");
+__FBSDID("$FreeBSD: head/sys/boot/i386/gptboot/gptboot.c 235988 2012-05-25 09:36:39Z gleb $");
 
 #include <sys/param.h>
 #include <sys/gpt.h>
@@ -90,14 +90,13 @@
 void exit(int);
 static void load(void);
 static int parse(char *, int *);
-static int xfsread(ino_t, void *, size_t);
 static int dskread(void *, daddr_t, unsigned);
 static uint32_t memsize(void);
 
 #include "ufsread.c"
 
 static inline int
-xfsread(ino_t inode, void *buf, size_t nbyte)
+xfsread(ufs_ino_t inode, void *buf, size_t nbyte)
 {
 
 	if ((size_t)fsread(inode, buf, nbyte) != nbyte) {
@@ -138,7 +137,7 @@
 {
 	char cmd[512], cmdtmp[512];
 	int autoboot, dskupdated;
-	ino_t ino;
+	ufs_ino_t ino;
 
 	dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base);
 	v86.ctl = V86_FLAGS;
@@ -247,7 +246,7 @@
     static Elf32_Phdr ep[2];
     static Elf32_Shdr es[2];
     caddr_t p;
-    ino_t ino;
+    ufs_ino_t ino;
     uint32_t addr, x;
     int fmt, i, j;
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/i386/libi386/Makefile
--- a/head/sys/boot/i386/libi386/Makefile	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/i386/libi386/Makefile	Wed Jul 25 16:45:04 2012 +0300
@@ -1,4 +1,4 @@
-# $FreeBSD: head/sys/boot/i386/libi386/Makefile 232263 2012-02-28 18:30:18Z dim $
+# $FreeBSD: head/sys/boot/i386/libi386/Makefile 235329 2012-05-12 09:03:30Z avg $
 #
 LIB=			i386
 INTERNALLIB=
@@ -9,6 +9,8 @@
 	elf64_freebsd.c \
 	i386_copy.c i386_module.c nullconsole.c pxe.c pxetramp.s \
 	smbios.c time.c vidconsole.c amd64_tramp.S spinconsole.c
+.PATH:	${.CURDIR}/../../zfs
+SRCS+=	devicename_stubs.c
 
 # Enable PXE TFTP or NFS support, not both.
 .if defined(LOADER_TFTP_SUPPORT)
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/i386/libi386/biosdisk.c
--- a/head/sys/boot/i386/libi386/biosdisk.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/i386/libi386/biosdisk.c	Wed Jul 25 16:45:04 2012 +0300
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/boot/i386/libi386/biosdisk.c 226748 2011-10-25 19:54:06Z jhb $");
+__FBSDID("$FreeBSD: head/sys/boot/i386/libi386/biosdisk.c 235155 2012-05-09 08:05:50Z avg $");
 
 /*
  * BIOS disk device handling.
@@ -55,7 +55,6 @@
 #define BIOS_NUMDRIVES		0x475
 #define BIOSDISK_SECSIZE	512
 #define BUFSIZE			(1 * BIOSDISK_SECSIZE)
-#define	MAXBDDEV		MAXDEV
 
 #define DT_ATAPI		0x10		/* disk type for ATAPI floppies */
 #define WDMAJOR			0		/* major numbers for devices we frontend for */
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/i386/libi386/biospnp.c
--- a/head/sys/boot/i386/libi386/biospnp.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/i386/libi386/biospnp.c	Wed Jul 25 16:45:04 2012 +0300
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/boot/i386/libi386/biospnp.c 236213 2012-05-29 01:48:06Z kevlo $");
 
 /*
  * PnP BIOS enumerator.
@@ -276,6 +276,7 @@
 	    break;
 	}
     }
+    va_end(ap);
 
     /* BIOS segment last */
     *(u_int16_t *)argp = pnp_Icheck->pnp_rmds;
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/i386/libi386/devicename.c
--- a/head/sys/boot/i386/libi386/devicename.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/i386/libi386/devicename.c	Wed Jul 25 16:45:04 2012 +0300
@@ -25,13 +25,14 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/boot/i386/libi386/devicename.c 235329 2012-05-12 09:03:30Z avg $");
 
 #include <stand.h>
 #include <string.h>
 #include <sys/disklabel.h>
 #include "bootstrap.h"
 #include "libi386.h"
+#include "../zfs/libzfs.h"
 
 static int	i386_parsedev(struct i386_devdesc **dev, const char *devspec, const char **path);
 
@@ -171,7 +172,6 @@
 
     case DEVT_CD:
     case DEVT_NET:
-    case DEVT_ZFS:
 	unit = 0;
 
 	if (*np && (*np != ':')) {
@@ -192,7 +192,11 @@
 	if (path != NULL)
 	    *path = (*cp == 0) ? cp : cp + 1;
 	break;
-
+    case DEVT_ZFS:
+	err = zfs_parsedev((struct zfs_devdesc *)idev, np, path);
+	if (err != 0)
+	    goto fail;
+	break;
     default:
 	err = EINVAL;
 	goto fail;
@@ -247,9 +251,10 @@
 	break;
 
     case DEVT_NET:
-    case DEVT_ZFS:
 	sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit);
 	break;
+    case DEVT_ZFS:
+	return(zfs_fmtdev(vdev));
     }
     return(buf);
 }
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/i386/libi386/libi386.h
--- a/head/sys/boot/i386/libi386/libi386.h	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/i386/libi386/libi386.h	Wed Jul 25 16:45:04 2012 +0300
@@ -23,14 +23,15 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/sys/boot/i386/libi386/libi386.h 229435 2012-01-03 22:36:12Z kib $
+ * $FreeBSD: head/sys/boot/i386/libi386/libi386.h 235329 2012-05-12 09:03:30Z avg $
  */
 
 
 /*
  * i386 fully-qualified device descriptor.
  * Note, this must match the 'struct devdesc' declaration
- * in bootstrap.h.
+ * in bootstrap.h and also with struct zfs_devdesc for zfs
+ * support.
  */
 struct i386_devdesc
 {
@@ -49,6 +50,12 @@
 	{
 	    void	*data;
 	} bioscd;
+	struct
+	{
+	    void	*data;
+	    uint64_t	pool_guid;
+	    uint64_t	root_guid;
+	} zfs;
     } d_kind;
 };
 
@@ -58,7 +65,8 @@
 
 extern struct devdesc	currdev;	/* our current device */
 
-#define MAXDEV	31			/* maximum number of distinct devices */
+#define MAXDEV		31		/* maximum number of distinct devices */
+#define MAXBDDEV	MAXDEV
 
 /* exported devices XXX rename? */
 extern struct devsw bioscd;
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/i386/loader/Makefile
--- a/head/sys/boot/i386/loader/Makefile	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/i386/loader/Makefile	Wed Jul 25 16:45:04 2012 +0300
@@ -1,4 +1,4 @@
-# $FreeBSD: head/sys/boot/i386/loader/Makefile 227726 2011-11-19 14:42:06Z miwi $
+# $FreeBSD: head/sys/boot/i386/loader/Makefile 235537 2012-05-17 10:11:18Z gber $
 
 .include <bsd.own.mk>
 MK_SSP=		no
@@ -20,9 +20,7 @@
 # Set by zfsloader Makefile
 .if defined(LOADER_ZFS_SUPPORT)
 CFLAGS+=	-DLOADER_ZFS_SUPPORT
-LIBZFS=		${.OBJDIR}/../../zfs/libzfsboot.a
-.else
-LIBZFS=
+LIBZFSBOOT=	${.OBJDIR}/../../zfs/libzfsboot.a
 .endif
 
 # Enable PXE TFTP or NFS support, not both.
@@ -55,6 +53,9 @@
 .if !defined(LOADER_NO_GPT_SUPPORT)
 CFLAGS+=	-DLOADER_GPT_SUPPORT
 .endif
+.if defined(LOADER_NANDFS_SUPPORT)
+CFLAGS+=	-DLOADER_NANDFS_SUPPORT
+.endif
 
 # Always add MI sources
 .PATH:		${.CURDIR}/../../common
@@ -119,8 +120,8 @@
 # XXX crt0.o needs to be first for pxeboot(8) to work
 OBJS=	${BTXCRT}
 
-DPADD=	${LIBFICL} ${LIBFIREWIRE} ${LIBZFS} ${LIBI386} ${LIBSTAND}
-LDADD=	${LIBFICL} ${LIBFIREWIRE} ${LIBZFS} ${LIBI386} ${LIBSTAND}
+DPADD=	${LIBFICL} ${LIBFIREWIRE} ${LIBZFSBOOT} ${LIBI386} ${LIBSTAND}
+LDADD=	${LIBFICL} ${LIBFIREWIRE} ${LIBZFSBOOT} ${LIBI386} ${LIBSTAND}
 
 .include <bsd.prog.mk>
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/i386/loader/conf.c
--- a/head/sys/boot/i386/loader/conf.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/i386/loader/conf.c	Wed Jul 25 16:45:04 2012 +0300
@@ -25,11 +25,14 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/boot/i386/loader/conf.c 235537 2012-05-17 10:11:18Z gber $");
 
 #include <stand.h>
 #include <bootstrap.h>
 #include "libi386/libi386.h"
+#if defined(LOADER_ZFS_SUPPORT)
+#include "../zfs/libzfs.h"
+#endif
 
 /*
  * We could use linker sets for some or all of these, but
@@ -50,10 +53,6 @@
 extern struct devsw fwohci;
 #endif
 
-#if defined(LOADER_ZFS_SUPPORT)
-extern struct devsw zfs_dev;
-#endif
-
 /* Exported for libstand */
 struct devsw *devsw[] = {
     &bioscd,
@@ -70,15 +69,14 @@
     NULL
 };
 
-#if defined(LOADER_ZFS_SUPPORT)
-extern struct fs_ops zfs_fsops;
-#endif
-
 struct fs_ops *file_system[] = {
     &ufs_fsops,
     &ext2fs_fsops,
     &dosfs_fsops,
     &cd9660_fsops,
+#if defined(LOADER_NANDFS_SUPPORT)
+    &nandfs_fsops,
+#endif
     &splitfs_fsops,
 #if defined(LOADER_ZFS_SUPPORT)
     &zfs_fsops,
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/i386/loader/main.c
--- a/head/sys/boot/i386/loader/main.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/i386/loader/main.c	Wed Jul 25 16:45:04 2012 +0300
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/boot/i386/loader/main.c 235329 2012-05-12 09:03:30Z avg $");
 
 /*
  * MD bootstrap main() and assorted miscellaneous
@@ -33,34 +33,28 @@
  */
 
 #include <stand.h>
+#include <stddef.h>
 #include <string.h>
 #include <machine/bootinfo.h>
 #include <machine/psl.h>
 #include <sys/reboot.h>
 
 #include "bootstrap.h"
+#include "common/bootargs.h"
 #include "libi386/libi386.h"
 #include "btxv86.h"
 
-#define	KARGS_FLAGS_CD		0x1
-#define	KARGS_FLAGS_PXE		0x2
-#define	KARGS_FLAGS_ZFS		0x4
+#ifdef LOADER_ZFS_SUPPORT
+#include "../zfs/libzfs.h"
+#endif
+
+CTASSERT(sizeof(struct bootargs) == BOOTARGS_SIZE);
+CTASSERT(offsetof(struct bootargs, bootinfo) == BA_BOOTINFO);
+CTASSERT(offsetof(struct bootargs, bootflags) == BA_BOOTFLAGS);
+CTASSERT(offsetof(struct bootinfo, bi_size) == BI_SIZE);
 
 /* Arguments passed in from the boot1/boot2 loader */
-static struct 
-{
-    u_int32_t	howto;
-    u_int32_t	bootdev;
-    u_int32_t	bootflags;
-    union {
-	struct {
-	    u_int32_t	pxeinfo;
-	    u_int32_t	res2;
-	};
-	uint64_t	zfspool;
-    };
-    u_int32_t	bootinfo;
-} *kargs;
+static struct bootargs *kargs;
 
 static u_int32_t	initial_howto;
 static u_int32_t	initial_bootdev;
@@ -72,6 +66,9 @@
 static int		isa_inb(int port);
 static void		isa_outb(int port, int value);
 void			exit(int code);
+#ifdef LOADER_ZFS_SUPPORT
+static void		i386_zfs_probe(void);
+#endif
 
 /* from vers.c */
 extern	char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[];
@@ -163,6 +160,9 @@
     archsw.arch_readin = i386_readin;
     archsw.arch_isainb = isa_inb;
     archsw.arch_isaoutb = isa_outb;
+#ifdef LOADER_ZFS_SUPPORT
+    archsw.arch_zfs_probe = i386_zfs_probe;
+#endif
 
     /*
      * March through the device switch probing for things.
@@ -206,8 +206,11 @@
 static void
 extract_currdev(void)
 {
-    struct i386_devdesc	new_currdev;
-    int			biosdev = -1;
+    struct i386_devdesc		new_currdev;
+#ifdef LOADER_ZFS_SUPPORT
+    struct zfs_boot_args	*zargs;
+#endif
+    int				biosdev = -1;
 
     /* Assume we are booting from a BIOS disk by default */
     new_currdev.d_dev = &biosdisk;
@@ -228,6 +231,24 @@
 	    new_currdev.d_kind.biosdisk.partition = 0;
 	    biosdev = -1;
 	}
+#ifdef LOADER_ZFS_SUPPORT
+    } else if ((kargs->bootflags & KARGS_FLAGS_ZFS) != 0) {
+	zargs = NULL;
+	/* check for new style extended argument */
+	if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0)
+	    zargs = (struct zfs_boot_args *)(kargs + 1);
+
+	if (zargs != NULL && zargs->size >= sizeof(*zargs)) {
+	    /* sufficient data is provided */
+	    new_currdev.d_kind.zfs.pool_guid = zargs->pool;
+	    new_currdev.d_kind.zfs.root_guid = zargs->root;
+	} else {
+	    /* old style zfsboot block */
+	    new_currdev.d_kind.zfs.pool_guid = kargs->zfspool;
+	    new_currdev.d_kind.zfs.root_guid = 0;
+	}
+	new_currdev.d_dev = &zfs_dev;
+#endif
     } else if ((initial_bootdev & B_MAGICMASK) != B_DEVMAGIC) {
 	/* The passed-in boot device is bad */
 	new_currdev.d_kind.biosdisk.slice = -1;
@@ -248,7 +269,7 @@
 	    biosdev = 0x80 + B_UNIT(initial_bootdev);		/* assume harddisk */
     }
     new_currdev.d_type = new_currdev.d_dev->dv_type;
-    
+
     /*
      * If we are booting off of a BIOS disk and we didn't succeed in determining
      * which one we booted off of, just use disk0: as a reasonable default.
@@ -259,33 +280,11 @@
 	       "Guessed BIOS device 0x%x not found by probes, defaulting to disk0:\n", biosdev);
 	new_currdev.d_unit = 0;
     }
+
     env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev),
 	       i386_setcurrdev, env_nounset);
     env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&new_currdev), env_noset,
 	       env_nounset);
-
-#ifdef LOADER_ZFS_SUPPORT
-    /*
-     * If we were started from a ZFS-aware boot2, we can work out
-     * which ZFS pool we are booting from.
-     */
-    if (kargs->bootflags & KARGS_FLAGS_ZFS) {
-	/*
-	 * Dig out the pool guid and convert it to a 'unit number'
-	 */
-	uint64_t guid;
-	int unit;
-	char devname[32];
-	extern int zfs_guid_to_unit(uint64_t);
-
-	guid = kargs->zfspool;
-	unit = zfs_guid_to_unit(guid);
-	if (unit >= 0) {
-	    sprintf(devname, "zfs%d", unit);
-	    setenv("currdev", devname, 1);
-	}
-    }
-#endif
 }
 
 COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
@@ -352,3 +351,30 @@
     }
 }
 
+#ifdef LOADER_ZFS_SUPPORT
+static void
+i386_zfs_probe(void)
+{
+    char devname[32];
+    int unit, slice;
+
+    /*
+     * Open all the disks we can find and see if we can reconstruct
+     * ZFS pools from them. Bogusly assumes that the disks are named
+     * diskN, diskNpM or diskNsM.
+     */
+    for (unit = 0; unit < MAXBDDEV; unit++) {
+	sprintf(devname, "disk%d:", unit);
+	if (zfs_probe_dev(devname, NULL) == ENXIO)
+	    continue;
+	for (slice = 1; slice <= 128; slice++) {
+	    sprintf(devname, "disk%dp%d:", unit, slice);
+	    zfs_probe_dev(devname, NULL);
+	}
+	for (slice = 1; slice <= 4; slice++) {
+	    sprintf(devname, "disk%ds%d:", unit, slice);
+	    zfs_probe_dev(devname, NULL);
+	}
+    }
+}
+#endif
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/i386/pxeldr/Makefile
--- a/head/sys/boot/i386/pxeldr/Makefile	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/i386/pxeldr/Makefile	Wed Jul 25 16:45:04 2012 +0300
@@ -1,4 +1,4 @@
-# $FreeBSD: head/sys/boot/i386/pxeldr/Makefile 232263 2012-02-28 18:30:18Z dim $
+# $FreeBSD: head/sys/boot/i386/pxeldr/Makefile 235219 2012-05-10 09:47:04Z avg $
 
 # Pick up ../Makefile.inc early.
 .include <bsd.init.mk>
@@ -23,6 +23,8 @@
 CFLAGS+=-DALWAYS_SERIAL
 .endif
 
+CFLAGS+=-I${.CURDIR}/../common
+
 LOADERBIN= ${.OBJDIR}/../loader/loader.bin
 
 CLEANFILES+= ${BOOT}.tmp
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/i386/pxeldr/pxeldr.S
--- a/head/sys/boot/i386/pxeldr/pxeldr.S	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/i386/pxeldr/pxeldr.S	Wed Jul 25 16:45:04 2012 +0300
@@ -12,7 +12,7 @@
  * warranties of merchantability and fitness for a particular
  * purpose.
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/boot/i386/pxeldr/pxeldr.S 235219 2012-05-10 09:47:04Z avg $
  */
 
 /*
@@ -26,6 +26,7 @@
  */
 
 #include <sys/reboot.h>
+#include <bootargs.h>
 
 /*
  * Memory locations.
@@ -50,11 +51,6 @@
 		.set AOUT_ENTRY,0x14		# entry point
 		.set AOUT_HEADER,MEM_PAGE_SIZE	# size of the a.out header
 /*
- * Flags for kargs->bootflags
- */
-		.set KARGS_FLAGS_PXE,0x2	# flag to indicate booting from
-						#  PXE loader
-/*
  * Segment selectors.
  */
 		.set SEL_SDATA,0x8		# Supervisor data
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/i386/zfsboot/zfsboot.c
--- a/head/sys/boot/i386/zfsboot/zfsboot.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/i386/zfsboot/zfsboot.c	Wed Jul 25 16:45:04 2012 +0300
@@ -14,7 +14,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/boot/i386/zfsboot/zfsboot.c 234339 2012-04-16 10:43:06Z avg $");
+__FBSDID("$FreeBSD: head/sys/boot/i386/zfsboot/zfsboot.c 235329 2012-05-12 09:03:30Z avg $");
 
 #include <sys/param.h>
 #include <sys/errno.h>
@@ -41,9 +41,9 @@
 #include "drv.h"
 #include "util.h"
 #include "cons.h"
+#include "bootargs.h"
 
-/* Hint to loader that we came from ZFS */
-#define	KARGS_FLAGS_ZFS		0x4
+#include "libzfs.h"
 
 #define PATH_DOTCONFIG	"/boot.config"
 #define PATH_CONFIG	"/boot/config"
@@ -63,8 +63,6 @@
 #define TYPE_MAXHARD	TYPE_DA
 #define TYPE_FD		2
 
-#define	MAXBDDEV	31
-
 extern uint32_t _end;
 
 #ifdef GPT
@@ -95,9 +93,12 @@
 static char cmd[512];
 static char cmddup[512];
 static char kname[1024];
+static char rootname[256];
 static int comspeed = SIOSPD;
 static struct bootinfo bootinfo;
 static uint32_t bootdev;
+static struct zfs_boot_args zfsargs;
+static struct zfsmount zfsmount;
 
 vm_offset_t	high_heap_base;
 uint32_t	bios_basemem, bios_extmem, high_heap_size;
@@ -174,7 +175,7 @@
 /*
  * Current ZFS pool
  */
-spa_t *spa;
+static spa_t *spa;
 
 /*
  * A wrapper for dskread that doesn't have to worry about whether the
@@ -213,7 +214,7 @@
 xfsread(const dnode_phys_t *dnode, off_t *offp, void *buf, size_t nbyte)
 {
     if ((size_t)zfs_read(spa, dnode, offp, buf, nbyte) != nbyte) {
-	printf("Invalid %s\n", "format");
+	printf("Invalid format\n");
 	return -1;
     }
     return 0;
@@ -533,10 +534,12 @@
 	}
     }
 
-    zfs_mount_pool(spa);
-
-    if (zfs_lookup(spa, PATH_CONFIG, &dn) == 0 ||
-        zfs_lookup(spa, PATH_DOTCONFIG, &dn) == 0) {
+    if (zfs_spa_init(spa) != 0 || zfs_mount(spa, 0, &zfsmount) != 0) {
+	printf("%s: failed to mount default pool %s\n",
+	    BOOTPROG, spa->spa_name);
+	autoboot = 0;
+    } else if (zfs_lookup(&zfsmount, PATH_CONFIG, &dn) == 0 ||
+        zfs_lookup(&zfsmount, PATH_DOTCONFIG, &dn) == 0) {
 	off = 0;
 	zfs_read(spa, &dn, &off, cmd, sizeof(cmd));
     }
@@ -571,11 +574,17 @@
     /* Present the user with the boot2 prompt. */
 
     for (;;) {
-	if (!autoboot || !OPT_CHECK(RBX_QUIET))
-	    printf("\nFreeBSD/x86 boot\n"
-		   "Default: %s:%s\n"
-		   "boot: ",
-		   spa->spa_name, kname);
+	if (!autoboot || !OPT_CHECK(RBX_QUIET)) {
+	    printf("\nFreeBSD/x86 boot\n");
+	    if (zfs_rlookup(spa, zfsmount.rootobj, rootname) != 0)
+		printf("Default: %s:<0x%llx>:%s\n"
+		       "boot: ",
+		       spa->spa_name, zfsmount.rootobj, kname);
+	    else
+		printf("Default: %s:%s:%s\n"
+		       "boot: ",
+		       spa->spa_name, rootname, kname);
+	}
 	if (ioctrl & IO_SERIAL)
 	    sio_flush();
 	if (!autoboot || keyhit(5))
@@ -611,7 +620,8 @@
     uint32_t addr, x;
     int fmt, i, j;
 
-    if (zfs_lookup(spa, kname, &dn)) {
+    if (zfs_lookup(&zfsmount, kname, &dn)) {
+	printf("\nCan't find %s\n", kname);
 	return;
     }
     off = 0;
@@ -685,12 +695,16 @@
     }
     bootinfo.bi_esymtab = VTOP(p);
     bootinfo.bi_kernelname = VTOP(kname);
+    zfsargs.size = sizeof(zfsargs);
+    zfsargs.pool = zfsmount.spa->spa_guid;
+    zfsargs.root = zfsmount.rootobj;
     __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
 	   bootdev,
-	   KARGS_FLAGS_ZFS,
+	   KARGS_FLAGS_ZFS | KARGS_FLAGS_EXTARG,
 	   (uint32_t) spa->spa_guid,
 	   (uint32_t) (spa->spa_guid >> 32),
-	   VTOP(&bootinfo));
+	   VTOP(&bootinfo),
+	   zfsargs);
 }
 
 static int
@@ -742,7 +756,7 @@
 	} if (c == '?') {
 	    dnode_phys_t dn;
 
-	    if (zfs_lookup(spa, arg, &dn) == 0) {
+	    if (zfs_lookup(&zfsmount, arg, &dn) == 0) {
 		zap_list(spa, &dn);
 	    }
 	    return -1;
@@ -764,17 +778,32 @@
 	    q = (char *) strchr(arg, ':');
 	    if (q) {
 		spa_t *newspa;
+		uint64_t newroot;
 
 		*q++ = 0;
 		newspa = spa_find_by_name(arg);
 		if (newspa) {
+		    arg = q;
 		    spa = newspa;
-		    zfs_mount_pool(spa);
+		    newroot = 0;
+		    q = (char *) strchr(arg, ':');
+		    if (q) {
+			*q++ = 0;
+			if (zfs_lookup_dataset(spa, arg, &newroot)) {
+			    printf("\nCan't find dataset %s in ZFS pool %s\n",
+			        arg, spa->spa_name);
+			    return -1;
+			}
+			arg = q;
+		    }
+		    if (zfs_mount(spa, newroot, &zfsmount)) {
+			printf("\nCan't mount ZFS dataset\n");
+			return -1;
+		    }
 		} else {
 		    printf("\nCan't find ZFS pool %s\n", arg);
 		    return -1;
 		}
-		arg = q;
 	    }
 	    if ((i = ep - arg)) {
 		if ((size_t)i >= sizeof(kname))
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/ofw/libofw/Makefile
--- a/head/sys/boot/ofw/libofw/Makefile	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/ofw/libofw/Makefile	Wed Jul 25 16:45:04 2012 +0300
@@ -1,4 +1,4 @@
-# $FreeBSD$
+# $FreeBSD: head/sys/boot/ofw/libofw/Makefile 235364 2012-05-12 20:27:33Z avg $
 
 LIB=		ofw
 INTERNALLIB=
@@ -6,6 +6,8 @@
 SRCS=	devicename.c elf_freebsd.c ofw_console.c ofw_copy.c ofw_disk.c \
 	ofw_memory.c ofw_module.c ofw_net.c ofw_reboot.c \
 	ofw_time.c openfirm.c
+.PATH:	${.CURDIR}/../../zfs
+SRCS+=  devicename_stubs.c
 
 CFLAGS+=	-I${.CURDIR}/../../../../lib/libstand/
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/ofw/libofw/devicename.c
--- a/head/sys/boot/ofw/libofw/devicename.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/ofw/libofw/devicename.c	Wed Jul 25 16:45:04 2012 +0300
@@ -25,10 +25,13 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/boot/ofw/libofw/devicename.c 235364 2012-05-12 20:27:33Z avg $");
 
 #include <stand.h>
+
+#include "bootstrap.h"
 #include "libofw.h"
+#include "../zfs/libzfs.h"
 
 static int ofw_parsedev(struct ofw_devdesc **, const char *, const char **);
 
@@ -76,8 +79,10 @@
     phandle_t		handle;
     const char		*p;
     const char		*s;
+    char		*ep;
     char		name[256];
     char		type[64];
+    int			err;
     int			len;
     int			i;
 
@@ -87,9 +92,10 @@
 	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 +115,15 @@
     strcpy(idev->d_path, name);
     idev->d_dev = dv;
     idev->d_type = dv->dv_type;
+    if (idev->d_type == DEVT_ZFS) {
+	p = devspec + strlen(dv->dv_name);
+	err = zfs_parsedev((struct zfs_devdesc *)idev, p, path);
+	if (err != 0) {
+	    free(idev);
+	    return (err);
+	}
+    }
+
     if (dev == NULL) {
 	free(idev);
     } else {
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/ofw/libofw/libofw.h
--- a/head/sys/boot/ofw/libofw/libofw.h	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/ofw/libofw/libofw.h	Wed Jul 25 16:45:04 2012 +0300
@@ -22,7 +22,7 @@
  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/boot/ofw/libofw/libofw.h 235364 2012-05-12 20:27:33Z avg $
  */
 
 #include "openfirm.h"
@@ -33,7 +33,13 @@
 	int		d_type;
 	int		d_unit;
 	ihandle_t	d_handle;
-	char		d_path[256];
+	union {
+		char			d_path[256];
+		struct {
+			uint64_t	pool_guid;
+			uint64_t	root_guid;
+		};
+	};
 };
 
 extern int	ofw_getdev(void **vdev, const char *devspec, const char **path);
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/ofw/libofw/ofw_disk.c
--- a/head/sys/boot/ofw/libofw/ofw_disk.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/ofw/libofw/ofw_disk.c	Wed Jul 25 16:45:04 2012 +0300
@@ -24,14 +24,13 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/boot/ofw/libofw/ofw_disk.c 236579 2012-06-04 20:45:33Z marius $");
 
 /*
  * Disk I/O routines using Open Firmware
  */
 
 #include <sys/param.h>
-#include <sys/queue.h>
 
 #include <netinet/in.h>
 
@@ -43,8 +42,8 @@
 #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 @@
 	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)
 {
 
 }
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/pc98/boot2/boot2.c
--- a/head/sys/boot/pc98/boot2/boot2.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/pc98/boot2/boot2.c	Wed Jul 25 16:45:04 2012 +0300
@@ -15,7 +15,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/boot/pc98/boot2/boot2.c 232784 2012-03-10 15:08:37Z nyan $");
+__FBSDID("$FreeBSD: head/sys/boot/pc98/boot2/boot2.c 235988 2012-05-25 09:36:39Z gleb $");
 
 #include <sys/param.h>
 #include <sys/disklabel.h>
@@ -140,7 +140,6 @@
 void exit(int);
 static void load(void);
 static int parse(void);
-static int xfsread(ino_t, void *, size_t);
 static int dskread(void *, unsigned, unsigned);
 static void printf(const char *,...);
 static void putchar(int);
@@ -172,7 +171,7 @@
 #include "ufsread.c"
 
 static inline int
-xfsread(ino_t inode, void *buf, size_t nbyte)
+xfsread(ufs_ino_t inode, void *buf, size_t nbyte)
 {
     if ((size_t)fsread(inode, buf, nbyte) != nbyte) {
 	printf("Invalid %s\n", "format");
@@ -351,7 +350,7 @@
     int i;
 #endif
     uint8_t autoboot;
-    ino_t ino;
+    ufs_ino_t ino;
     size_t nbyte;
 
     dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base);
@@ -446,7 +445,7 @@
     static Elf32_Phdr ep[2];
     static Elf32_Shdr es[2];
     caddr_t p;
-    ino_t ino;
+    ufs_ino_t ino;
     uint32_t addr;
     int i, j;
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/pc98/btx/btx/Makefile
--- a/head/sys/boot/pc98/btx/btx/Makefile	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/pc98/btx/btx/Makefile	Wed Jul 25 16:45:04 2012 +0300
@@ -1,4 +1,4 @@
-# $FreeBSD: head/sys/boot/pc98/btx/btx/Makefile 232263 2012-02-28 18:30:18Z dim $
+# $FreeBSD: head/sys/boot/pc98/btx/btx/Makefile 235264 2012-05-11 09:46:17Z avg $
 
 PROG=	btx
 INTERNALPROG=
@@ -12,6 +12,7 @@
 .endif
 
 CFLAGS+=-DBTX_FLAGS=${BOOT_BTX_FLAGS}
+CFLAGS+=-I${.CURDIR}/../../../i386/common
 
 .if defined(BTX_SERIAL)
 BOOT_COMCONSOLE_PORT?= 0x238
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/pc98/btx/btx/btx.S
--- a/head/sys/boot/pc98/btx/btx/btx.S	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/pc98/btx/btx/btx.S	Wed Jul 25 16:45:04 2012 +0300
@@ -12,9 +12,11 @@
  * warranties of merchantability and fitness for a particular
  * purpose.
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/boot/pc98/btx/btx/btx.S 235264 2012-05-11 09:46:17Z avg $
  */
 
+#include <bootargs.h>
+
 /*
  * Memory layout.
  */
@@ -205,7 +207,7 @@
 		andl $0x7,%eax
 		incl %eax
 		shll $0x11,%eax			# To bytes
-		subl $0x1000,%eax		# Less arg space
+		subl $ARGSPACE,%eax		# Less arg space
 		subl %edx,%eax			# Less base
 		movb $SEL_UDATA,%cl		# User data selector
 		pushl %ecx			# Set SS
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/pc98/btx/btxldr/Makefile
--- a/head/sys/boot/pc98/btx/btxldr/Makefile	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/pc98/btx/btxldr/Makefile	Wed Jul 25 16:45:04 2012 +0300
@@ -1,4 +1,4 @@
-# $FreeBSD: head/sys/boot/pc98/btx/btxldr/Makefile 232263 2012-02-28 18:30:18Z dim $
+# $FreeBSD: head/sys/boot/pc98/btx/btxldr/Makefile 235264 2012-05-11 09:46:17Z avg $
 
 PROG=	btxldr
 INTERNALPROG=
@@ -6,6 +6,7 @@
 SRCS=	btxldr.S
 
 CFLAGS+=-DLOADER_ADDRESS=${LOADER_ADDRESS}
+CFLAGS+=-I${.CURDIR}/../../../i386/common
 
 .if defined(BTXLDR_VERBOSE)
 CFLAGS+=-DBTXLDR_VERBOSE
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/pc98/btx/btxldr/btxldr.S
--- a/head/sys/boot/pc98/btx/btxldr/btxldr.S	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/pc98/btx/btxldr/btxldr.S	Wed Jul 25 16:45:04 2012 +0300
@@ -12,7 +12,7 @@
  * warranties of merchantability and fitness for a particular
  * purpose.
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/boot/pc98/btx/btxldr/btxldr.S 235264 2012-05-11 09:46:17Z avg $
  */
 
 /*
@@ -20,6 +20,8 @@
  * real thing should probably be more flexible, and in C.
  */
 
+#include <bootargs.h>
+
 /*
  * Memory locations.
  */
@@ -105,7 +107,7 @@
 		call hexout			#  stack
 		call putstr			#  pointer
 		movl $m_args,%esi		# Format string
-		leal 0x4(%esp,1),%ebx		# First argument
+		leal 0x4(%esp),%ebx		# First argument
 		movl $0x6,%ecx			# Count
 start.1:	movl (%ebx),%eax		# Get argument and
 		addl $0x4,%ebx			#  bump pointer
@@ -113,24 +115,28 @@
 		loop start.1			# Till done
 		call putstr			# End message
 #endif
-		movl $0x48,%ecx 		# Allocate space
-		subl %ecx,%ebp			#  for bootinfo
-		movl 0x18(%esp,1),%esi		# Source: bootinfo
+		movl BA_BOOTINFO+4(%esp),%esi	# Source: bootinfo
 		cmpl $0x0, %esi			# If the bootinfo pointer
 		je start_null_bi		#  is null, don't copy it
+		movl BI_SIZE(%esi),%ecx 	# Allocate space
+		subl %ecx,%ebp			#  for bootinfo
 		movl %ebp,%edi			# Destination
 		rep				# Copy
 		movsb				#  it
-		movl %ebp,0x18(%esp,1)		# Update pointer
+		movl %ebp,BA_BOOTINFO+4(%esp)	# Update pointer
+		movl %edi,%ebp			# Restore base pointer
 #ifdef BTXLDR_VERBOSE
 		movl $m_rel_bi,%esi		# Display
 		movl %ebp,%eax			#  bootinfo
 		call hexout			#  relocation
 		call putstr			#  message
 #endif
-start_null_bi:	movl $0x18,%ecx 		# Allocate space
-		subl %ecx,%ebp			#  for arguments
-		leal 0x4(%esp,1),%esi		# Source
+start_null_bi:	movl $BOOTARGS_SIZE,%ecx 	# Fixed size of arguments
+		testl $KARGS_FLAGS_EXTARG, BA_BOOTFLAGS+4(%esp) # Check for extra data
+		jz start_fixed			# Skip if the flag is not set
+		addl BOOTARGS_SIZE+4(%esp),%ecx	# Add size of variable args
+start_fixed:	subl $ARGOFF,%ebp		# Place args at fixed offset
+		leal 0x4(%esp),%esi		# Source
 		movl %ebp,%edi			# Destination
 		rep				# Copy
 		movsb				#  them
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/pc98/btx/lib/Makefile
--- a/head/sys/boot/pc98/btx/lib/Makefile	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/pc98/btx/lib/Makefile	Wed Jul 25 16:45:04 2012 +0300
@@ -1,9 +1,10 @@
-# $FreeBSD$
+# $FreeBSD: head/sys/boot/pc98/btx/lib/Makefile 235264 2012-05-11 09:46:17Z avg $
 
 PROG=	crt0.o
 INTERNALPROG=
 NO_MAN=
-SRCS=	btxcsu.s btxsys.s btxv86.s
+SRCS=	btxcsu.S btxsys.s btxv86.s
+CFLAGS+=-I${.CURDIR}/../../../i386/common
 LDFLAGS=-Wl,-r
 
 .include <bsd.prog.mk>
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/pc98/btx/lib/btxcsu.S
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/boot/pc98/btx/lib/btxcsu.S	Wed Jul 25 16:45:04 2012 +0300
@@ -0,0 +1,49 @@
+#
+# Copyright (c) 1998 Robert Nordier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are freely
+# permitted provided that the above copyright notice and this
+# paragraph and the following disclaimer are duplicated in all
+# such forms.
+#
+# This software is provided "AS IS" and without any express or
+# implied warranties, including, without limitation, the implied
+# warranties of merchantability and fitness for a particular
+# purpose.
+#
+
+# $FreeBSD: head/sys/boot/pc98/btx/lib/btxcsu.S 235264 2012-05-11 09:46:17Z avg $
+
+#
+# BTX C startup code (ELF).
+#
+
+#include <bootargs.h>
+
+#
+# Globals.
+#
+		.global _start
+#
+# Client entry point.
+#
+_start: 	cld
+		pushl %eax
+		movl $_edata,%edi 
+		movl $_end,%ecx 
+		subl %edi, %ecx
+		xorb %al, %al
+		rep
+		stosb
+		popl __base
+		movl %esp,%eax			# Set
+		addl $ARGADJ,%eax		#  argument
+		movl %eax,__args		#  pointer
+		call main			# Invoke client main()
+		call exit			# Invoke client exit()
+#
+# Data.
+#
+		.comm __base,4			# Client base address
+		.comm __args,4			# Client arguments
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/pc98/btx/lib/btxcsu.s
--- a/head/sys/boot/pc98/btx/lib/btxcsu.s	Wed Jul 25 16:42:35 2012 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-#
-# Copyright (c) 1998 Robert Nordier
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms are freely
-# permitted provided that the above copyright notice and this
-# paragraph and the following disclaimer are duplicated in all
-# such forms.
-#
-# This software is provided "AS IS" and without any express or
-# implied warranties, including, without limitation, the implied
-# warranties of merchantability and fitness for a particular
-# purpose.
-#
-
-# $FreeBSD$
-
-#
-# BTX C startup code (ELF).
-#
-
-#
-# Globals.
-#
-		.global _start
-#
-# Constants.
-#
-		.set ARGADJ,0xfa0		# Argument adjustment
-#
-# Client entry point.
-#
-_start: 	cld
-		pushl %eax
-		movl $_edata,%edi 
-		movl $_end,%ecx 
-		subl %edi, %ecx
-		xorb %al, %al
-		rep
-		stosb
-		popl __base
-		movl %esp,%eax			# Set
-		addl $ARGADJ,%eax		#  argument
-		movl %eax,__args		#  pointer
-		call main			# Invoke client main()
-		call exit			# Invoke client exit()
-#
-# Data.
-#
-		.comm __base,4			# Client base address
-		.comm __args,4			# Client arguments
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/pc98/cdboot/Makefile
--- a/head/sys/boot/pc98/cdboot/Makefile	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/pc98/cdboot/Makefile	Wed Jul 25 16:45:04 2012 +0300
@@ -1,10 +1,12 @@
-# $FreeBSD$
+# $FreeBSD: head/sys/boot/pc98/cdboot/Makefile 235264 2012-05-11 09:46:17Z avg $
 
 PROG=	cdboot
 STRIP=
 BINMODE=${NOBINMODE}
 NO_MAN=
-SRCS=	${PROG}.s
+SRCS=	${PROG}.S
+
+CFLAGS+=-I${.CURDIR}/../../i386/common
 
 ORG=	0x0000
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/pc98/cdboot/cdboot.S
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/boot/pc98/cdboot/cdboot.S	Wed Jul 25 16:45:04 2012 +0300
@@ -0,0 +1,808 @@
+#
+# Copyright (c) 2006 TAKAHASHI Yoshihiro <nyan at FreeBSD.org>
+# Copyright (c) 2001 John Baldwin <jhb at FreeBSD.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the author nor the names of any co-contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+# $FreeBSD: head/sys/boot/pc98/cdboot/cdboot.S 235264 2012-05-11 09:46:17Z avg $
+
+#include <bootargs.h>
+
+#
+# Basically, we first create a set of boot arguments to pass to the loaded
+# binary.  Then we attempt to load /boot/loader from the CD we were booted
+# off of. 
+#
+
+#
+# Memory locations.
+#
+		.set STACK_OFF,0x6000		# Stack offset
+		.set LOAD_SEG,0x0700		# Load segment
+		.set LOAD_SIZE,2048		# Load size
+		.set DAUA,0x0584		# DA/UA
+
+		.set MEM_PAGE_SIZE,0x1000	# memory page size, 4k
+		.set MEM_ARG,0x900		# Arguments at start
+		.set MEM_ARG_BTX,0xa100		# Where we move them to so the
+						#  BTX client can see them
+		.set MEM_ARG_SIZE,0x18		# Size of the arguments
+		.set MEM_BTX_ADDRESS,0x9000	# where BTX lives
+		.set MEM_BTX_ENTRY,0x9010	# where BTX starts to execute
+		.set MEM_BTX_OFFSET,MEM_PAGE_SIZE # offset of BTX in the loader
+		.set MEM_BTX_CLIENT,0xa000	# where BTX clients live
+#
+# PC98 machine type from sys/pc98/pc98/pc98_machdep.h
+#
+		.set MEM_SYS,		0xa100	# System common area segment
+		.set PC98_MACHINE_TYPE,	0x0620	# PC98 machine type
+		.set EPSON_ID,		0x0624	# EPSON machine id
+
+		.set M_NEC_PC98,	0x0001
+		.set M_EPSON_PC98,	0x0002
+		.set M_NOT_H98,		0x0010
+		.set M_H98,		0x0020
+		.set M_NOTE,		0x0040
+		.set M_NORMAL,		0x1000
+		.set M_8M,		0x8000
+#
+# Signature Constants
+#
+		.set SIG1_OFF,0x1fe		# Signature offset
+		.set SIG2_OFF,0x7fe		# Signature offset
+#
+# a.out header fields
+#
+		.set AOUT_TEXT,0x04		# text segment size
+		.set AOUT_DATA,0x08		# data segment size
+		.set AOUT_BSS,0x0c		# zero'd BSS size
+		.set AOUT_SYMBOLS,0x10		# symbol table
+		.set AOUT_ENTRY,0x14		# entry point
+		.set AOUT_HEADER,MEM_PAGE_SIZE	# size of the a.out header
+#
+# Segment selectors.
+#
+		.set SEL_SDATA,0x8		# Supervisor data
+		.set SEL_RDATA,0x10		# Real mode data
+		.set SEL_SCODE,0x18		# PM-32 code
+		.set SEL_SCODE16,0x20		# PM-16 code
+#
+# BTX constants
+#
+		.set INT_SYS,0x30		# BTX syscall interrupt
+#
+# Constants for reading from the CD.
+#
+		.set ERROR_TIMEOUT,0x90		# BIOS timeout on read
+		.set NUM_RETRIES,3		# Num times to retry
+		.set SECTOR_SIZE,0x800		# size of a sector
+		.set SECTOR_SHIFT,11		# number of place to shift
+		.set BUFFER_LEN,0x100		# number of sectors in buffer
+		.set MAX_READ,0xf800		# max we can read at a time
+		.set MAX_READ_SEC,MAX_READ >> SECTOR_SHIFT
+		.set MEM_READ_BUFFER,0x9000	# buffer to read from CD
+		.set MEM_VOLDESC,MEM_READ_BUFFER # volume descriptor
+		.set MEM_DIR,MEM_VOLDESC+SECTOR_SIZE # Lookup buffer
+		.set VOLDESC_LBA,0x10		# LBA of vol descriptor
+		.set VD_PRIMARY,1		# Primary VD
+		.set VD_END,255			# VD Terminator
+		.set VD_ROOTDIR,156		# Offset of Root Dir Record
+		.set DIR_LEN,0			# Offset of Dir Record length
+		.set DIR_EA_LEN,1		# Offset of EA length
+		.set DIR_EXTENT,2		# Offset of 64-bit LBA
+		.set DIR_SIZE,10		# Offset of 64-bit length
+		.set DIR_NAMELEN,32		# Offset of 8-bit name len
+		.set DIR_NAME,33		# Offset of dir name
+
+#
+# Program start.
+#
+		.code16
+		.globl start
+
+start:		jmp main
+
+		.org 4
+		.ascii "IPL1   "
+
+main:		cld
+
+		/* Setup the stack */
+		xor %ax,%ax
+		mov %ax,%ss
+		mov $STACK_OFF,%sp
+
+		push %ecx
+
+		/* Setup graphic screen */
+		mov $0x42,%ah			# 640x400
+		mov $0xc0,%ch
+		int $0x18
+		mov $0x40,%ah			# graph on
+		int $0x18
+
+		/* Setup text screen */
+		mov $0x0a00,%ax			# 80x25
+		int $0x18
+		mov $0x0c,%ah			# text on
+		int $0x18
+		mov $0x13,%ah			# cursor home
+		xor %dx,%dx
+		int $0x18
+		mov $0x11,%ah			# cursor on
+		int $0x18
+
+		/* Setup keyboard */
+		mov $0x03,%ah
+		int $0x18
+
+		/* Transfer PC-9801 system common area */
+		xor %ax,%ax
+		mov %ax,%si
+		mov %ax,%ds
+		mov %ax,%di
+		mov $MEM_SYS,%ax
+		mov %ax,%es
+		mov $0x0600,%cx
+		rep
+		movsb
+
+		/* Transfer EPSON machine type */
+		mov $0xfd00,%ax
+		mov %ax,%ds
+		mov (0x804),%eax
+		and $0x00ffffff,%eax
+		mov %eax,%es:(EPSON_ID)
+
+		/* Set machine type to PC98_SYSTEM_PARAMETER */
+		call machine_check
+
+		/* Load cdboot */
+		xor %ax,%ax
+		mov %ax,%ds
+		mov $0x06,%ah		/* Read data */
+		mov (DAUA),%al		/* Read drive */
+		pop %ecx		/* cylinder */
+		xor %dx,%dx		/* head / sector */
+		mov $LOAD_SEG,%bx	/* Load address */
+		mov %bx,%es
+		xor %bp,%bp
+		mov $LOAD_SIZE,%bx	/* Load size */
+		int $0x1b
+		mov $msg_readerr,%si
+		jc error
+
+		/* Jump to cdboot */
+		ljmp $LOAD_SEG,$cdboot
+
+#
+# Set machine type to PC98_SYSTEM_PARAMETER.
+#
+machine_check:	xor %edx,%edx
+		mov %dx,%ds
+		mov $MEM_SYS,%ax
+		mov %ax,%es
+
+		/* Wait V-SYNC */
+vsync.1:	inb $0x60,%al
+		test $0x20,%al
+		jnz vsync.1
+vsync.2:	inb $0x60,%al
+		test $0x20,%al
+		jz vsync.2
+
+		/* ANK 'A' font */
+		xor %al,%al
+		outb %al,$0xa1
+		mov $0x41,%al
+		outb %al,$0xa3
+
+		/* Get 'A' font from CG window */
+		push %ds
+		mov $0xa400,%ax
+		mov %ax,%ds
+		xor %eax,%eax
+		xor %bx,%bx
+		mov $4,%cx
+font.1:		add (%bx),%eax
+		add $4,%bx
+		loop font.1
+		pop %ds
+		cmp $0x6efc58fc,%eax
+		jnz m_epson
+
+m_pc98:		or $M_NEC_PC98,%edx
+		mov $0x0458,%bx
+		mov (%bx),%al
+		test $0x80,%al
+		jz m_not_h98
+		or $M_H98,%edx
+		jmp 1f
+m_epson:	or $M_EPSON_PC98,%edx
+m_not_h98:	or $M_NOT_H98,%edx
+
+1:		inb $0x42,%al
+		test $0x20,%al
+		jz 1f
+		or $M_8M,%edx
+
+1:		mov $0x0400,%bx
+		mov (%bx),%al
+		test $0x80,%al
+		jz 1f
+		or $M_NOTE,%edx
+
+1:		mov $PC98_MACHINE_TYPE,%bx
+		mov %edx,%es:(%bx)
+		ret
+
+#
+# Print out the error message at [SI], wait for a keypress, and then
+# reboot the machine.
+#
+error:		call putstr
+		mov $msg_keypress,%si
+		call putstr
+		xor %ax,%ax			# Get keypress
+		int $0x18
+		xor %ax,%ax			# CPU reset
+		outb %al,$0xf0
+halt:		hlt
+		jmp halt			# Spin
+
+#
+# Display a null-terminated string at [SI].
+#
+# Trashes: AX, BX, CX, DX, SI, DI
+#
+putstr:		push %ds
+		push %es
+		mov %cs,%ax
+		mov %ax,%ds
+		mov $0xa000,%ax
+		mov %ax,%es
+		mov cursor,%di
+		mov $0x00e1,%bx			# Attribute
+		mov $160,%cx
+putstr.0:	lodsb
+		testb %al,%al
+		jz putstr.done
+		cmp $0x0d,%al
+		jz putstr.cr
+		cmp $0x0a,%al
+		jz putstr.lf
+		mov %bl,%es:0x2000(%di)
+		stosb
+		inc %di
+		jmp putstr.move
+putstr.cr:	xor %dx,%dx
+		mov %di,%ax
+		div %cx
+		sub %dx,%di
+		jmp putstr.move
+putstr.lf:	add %cx,%di
+putstr.move:	mov %di,%dx
+		mov $0x13,%ah			# Move cursor
+		int $0x18
+		jmp putstr.0
+putstr.done:	mov %di,cursor
+		pop %es
+		pop %ds
+		ret
+
+#
+# Display a single char at [AL], but don't move a cursor.
+#
+putc:		push %es
+		push %di
+		push %bx
+		mov $0xa000,%bx
+		mov %bx,%es
+		mov cursor,%di
+		mov $0xe1,%bl			# Attribute
+		mov %bl,%es:0x2000(%di)
+		stosb
+		pop %bx
+		pop %di
+		pop %es
+		ret
+
+msg_readerr:	.asciz "Read Error\r\n"
+msg_keypress:	.asciz "\r\nPress any key to reboot\r\n"
+
+/* Boot signature */
+
+		.org SIG1_OFF,0x90
+
+		.word 0xaa55			# Magic number
+
+#
+# cdboot
+#
+cdboot:		mov %cs,%ax
+		mov %ax,%ds
+		xor %ax,%ax
+		mov %ax,%es
+		mov %es:(DAUA),%al		# Save BIOS boot device
+		mov %al,drive
+		mov %cx,cylinder		# Save BIOS boot cylinder
+
+		mov $msg_welcome,%si		# %ds:(%si) -> welcome message
+		call putstr			# display the welcome message
+#
+# Setup the arguments that the loader is expecting from boot[12]
+#
+		mov $msg_bootinfo,%si		# %ds:(%si) -> boot args message
+		call putstr			# display the message
+		mov $MEM_ARG,%bx		# %ds:(%bx) -> boot args
+		mov %bx,%di			# %es:(%di) -> boot args
+		xor %eax,%eax			# zero %eax
+		mov $(MEM_ARG_SIZE/4),%cx	# Size of arguments in 32-bit
+						#  dwords
+		rep				# Clear the arguments
+		stosl				#  to zero
+		mov drive,%dl			# Store BIOS boot device
+		mov %dl,%es:0x4(%bx)		#  in kargs->bootdev
+		or $KARGS_FLAGS_CD,%es:0x8(%bx)	# kargs->bootflags |=
+						#  KARGS_FLAGS_CD
+#
+# Load Volume Descriptor
+#
+		mov $VOLDESC_LBA,%eax		# Set LBA of first VD
+load_vd:	push %eax			# Save %eax
+		mov $1,%dh			# One sector
+		mov $MEM_VOLDESC,%ebx		# Destination
+		call read			# Read it in
+		cmpb $VD_PRIMARY,%es:(%bx)	# Primary VD?
+		je have_vd			# Yes
+		pop %eax			# Prepare to
+		inc %eax			#  try next
+		cmpb $VD_END,%es:(%bx)		# Last VD?
+		jne load_vd			# No, read next
+		mov $msg_novd,%si		# No VD
+		jmp error			# Halt
+have_vd:					# Have Primary VD
+#
+# Try to look up the loader binary using the paths in the loader_paths
+# array.
+#
+		mov $loader_paths,%si		# Point to start of array
+lookup_path:	push %si			# Save file name pointer
+		call lookup			# Try to find file
+		pop %di				# Restore file name pointer
+		jnc lookup_found		# Found this file
+		push %es
+		mov %cs,%ax
+		mov %ax,%es
+		xor %al,%al			# Look for next
+		mov $0xffff,%cx			#  path name by
+		repnz				#  scanning for
+		scasb				#  nul char
+		pop %es
+		mov %di,%si			# Point %si at next path
+		mov (%si),%al			# Get first char of next path
+		or %al,%al			# Is it double nul?
+		jnz lookup_path			# No, try it.
+		mov $msg_failed,%si		# Failed message
+		jmp error			# Halt
+lookup_found:					# Found a loader file
+#
+# Load the binary into the buffer.  Due to real mode addressing limitations
+# we have to read it in 64k chunks.
+#
+		mov %es:DIR_SIZE(%bx),%eax	# Read file length
+		add $SECTOR_SIZE-1,%eax		# Convert length to sectors
+		shr $SECTOR_SHIFT,%eax
+		cmp $BUFFER_LEN,%eax
+		jbe load_sizeok
+		mov $msg_load2big,%si		# Error message
+		jmp error
+load_sizeok:	movzbw %al,%cx			# Num sectors to read
+		mov %es:DIR_EXTENT(%bx),%eax	# Load extent
+		xor %edx,%edx
+		mov %es:DIR_EA_LEN(%bx),%dl
+		add %edx,%eax			# Skip extended
+		mov $MEM_READ_BUFFER,%ebx	# Read into the buffer
+load_loop:	mov %cl,%dh
+		cmp $MAX_READ_SEC,%cl		# Truncate to max read size
+		jbe load_notrunc
+		mov $MAX_READ_SEC,%dh
+load_notrunc:	sub %dh,%cl			# Update count
+		push %eax			# Save
+		call read			# Read it in
+		pop %eax			# Restore
+		add $MAX_READ_SEC,%eax		# Update LBA
+		add $MAX_READ,%ebx		# Update dest addr
+		jcxz load_done			# Done?
+		jmp load_loop			# Keep going
+load_done:
+#
+# Turn on the A20 address line
+#
+		xor %ax,%ax			# Turn A20 on
+		outb %al,$0xf2
+		mov $0x02,%al
+		outb %al,$0xf6
+#
+# Relocate the loader and BTX using a very lazy protected mode
+#
+		mov $msg_relocate,%si		# Display the
+		call putstr			#  relocation message
+		mov %es:(MEM_READ_BUFFER+AOUT_ENTRY),%edi # %edi is the destination
+		mov $(MEM_READ_BUFFER+AOUT_HEADER),%esi	# %esi is
+						#  the start of the text
+						#  segment
+		mov %es:(MEM_READ_BUFFER+AOUT_TEXT),%ecx # %ecx = length of the text
+						#  segment
+		push %edi			# Save entry point for later
+		lgdt gdtdesc			# setup our own gdt
+		cli				# turn off interrupts
+		mov %cr0,%eax			# Turn on
+		or $0x1,%al			#  protected
+		mov %eax,%cr0			#  mode
+		ljmp $SEL_SCODE,$pm_start	# long jump to clear the
+						#  instruction pre-fetch queue
+		.code32
+pm_start:	mov $SEL_SDATA,%ax		# Initialize
+		mov %ax,%ds			#  %ds and
+		mov %ax,%es			#  %es to a flat selector
+		rep				# Relocate the
+		movsb				#  text segment
+		add $(MEM_PAGE_SIZE - 1),%edi	# pad %edi out to a new page
+		and $~(MEM_PAGE_SIZE - 1),%edi #  for the data segment
+		mov MEM_READ_BUFFER+AOUT_DATA,%ecx # size of the data segment
+		rep				# Relocate the
+		movsb				#  data segment
+		mov MEM_READ_BUFFER+AOUT_BSS,%ecx # size of the bss
+		xor %eax,%eax			# zero %eax
+		add $3,%cl			# round %ecx up to
+		shr $2,%ecx			#  a multiple of 4
+		rep				# zero the
+		stosl				#  bss
+		mov MEM_READ_BUFFER+AOUT_ENTRY,%esi # %esi -> relocated loader
+		add $MEM_BTX_OFFSET,%esi	# %esi -> BTX in the loader
+		mov $MEM_BTX_ADDRESS,%edi	# %edi -> where BTX needs to go
+		movzwl 0xa(%esi),%ecx		# %ecx -> length of BTX
+		rep				# Relocate
+		movsb				#  BTX
+		ljmp $SEL_SCODE16,$pm_16	# Jump to 16-bit PM
+		.code16
+pm_16:		mov $SEL_RDATA,%ax		# Initialize
+		mov %ax,%ds			#  %ds and
+		mov %ax,%es			#  %es to a real mode selector
+		mov %cr0,%eax			# Turn off
+		and $~0x1,%al			#  protected
+		mov %eax,%cr0			#  mode
+		ljmp $LOAD_SEG,$pm_end		# Long jump to clear the
+						#  instruction pre-fetch queue
+pm_end:		sti				# Turn interrupts back on now
+#
+# Copy the BTX client to MEM_BTX_CLIENT
+#
+		mov %cs,%ax
+		mov %ax,%ds
+		xor %ax,%ax
+		mov %ax,%es
+		mov $MEM_BTX_CLIENT,%di		# Prepare to relocate
+		mov $btx_client,%si		#  the simple btx client
+		mov $(btx_client_end-btx_client),%cx # length of btx client
+		rep				# Relocate the
+		movsb				#  simple BTX client
+#
+# Copy the boot[12] args to where the BTX client can see them
+#
+		xor %ax,%ax
+		mov %ax,%ds
+		mov $MEM_ARG,%si		# where the args are at now
+		mov $MEM_ARG_BTX,%di		# where the args are moving to
+		mov $(MEM_ARG_SIZE/4),%cx	# size of the arguments in longs
+		rep				# Relocate
+		movsl				#  the words
+#
+# Save the entry point so the client can get to it later on
+#
+		pop %eax			# Restore saved entry point
+		stosl				#  and add it to the end of
+						#  the arguments
+#
+# Now we just start up BTX and let it do the rest
+#
+		mov $msg_jump,%si		# Display the
+		call putstr			#  jump message
+		ljmp $0,$MEM_BTX_ENTRY		# Jump to the BTX entry point
+
+#
+# Lookup the file in the path at [SI] from the root directory.
+#
+# Trashes: All but BX
+# Returns: CF = 0 (success), BX = pointer to record
+#          CF = 1 (not found)
+#
+lookup:		mov $VD_ROOTDIR+MEM_VOLDESC,%bx	# Root directory record
+		push %bx
+		push %si
+		mov $msg_lookup,%si		# Display lookup message
+		call putstr
+		pop %si
+		push %si
+		call putstr
+		mov $msg_lookup2,%si
+		call putstr
+		pop %si
+		pop %bx
+lookup_dir:	lodsb				# Get first char of path
+		cmp $0,%al			# Are we done?
+		je lookup_done			# Yes
+		cmp $'/',%al			# Skip path separator.
+		je lookup_dir
+		dec %si				# Undo lodsb side effect
+		call find_file			# Lookup first path item
+		jnc lookup_dir			# Try next component
+		mov $msg_lookupfail,%si		# Not found message
+		push %bx
+		call putstr
+		pop %bx
+		stc				# Set carry
+		ret
+lookup_done:	mov $msg_lookupok,%si		# Success message
+		push %bx
+		call putstr
+		pop %bx
+		clc				# Clear carry
+		ret
+
+#
+# Lookup file at [SI] in directory whose record is at [BX].
+#
+# Trashes: All but returns
+# Returns: CF = 0 (success), BX = pointer to record, SI = next path item
+#          CF = 1 (not found), SI = preserved
+#
+find_file:	mov %es:DIR_EXTENT(%bx),%eax	# Load extent
+		xor %edx,%edx
+		mov %es:DIR_EA_LEN(%bx),%dl
+		add %edx,%eax			# Skip extended attributes
+		mov %eax,rec_lba		# Save LBA
+		mov %es:DIR_SIZE(%bx),%eax	# Save size
+		mov %eax,rec_size
+		xor %cl,%cl			# Zero length
+		push %si			# Save
+ff.namelen:	inc %cl				# Update length
+		lodsb				# Read char
+		cmp $0,%al			# Nul?
+		je ff.namedone			# Yes
+		cmp $'/',%al			# Path separator?
+		jnz ff.namelen			# No, keep going
+ff.namedone:	dec %cl				# Adjust length and save
+		mov %cl,name_len
+		pop %si				# Restore
+ff.load:	mov rec_lba,%eax		# Load LBA
+		mov $MEM_DIR,%ebx		# Address buffer
+		mov $1,%dh			# One sector
+		call read			# Read directory block
+		incl rec_lba			# Update LBA to next block
+ff.scan:	mov %ebx,%edx			# Check for EOF
+		sub $MEM_DIR,%edx
+		cmp %edx,rec_size
+		ja ff.scan.1
+		stc				# EOF reached
+		ret
+ff.scan.1:	cmpb $0,%es:DIR_LEN(%bx)	# Last record in block?
+		je ff.nextblock
+		push %si			# Save
+		movzbw %es:DIR_NAMELEN(%bx),%si	# Find end of string
+ff.checkver:	cmpb $'0',%es:DIR_NAME-1(%bx,%si)	# Less than '0'?
+		jb ff.checkver.1
+		cmpb $'9',%es:DIR_NAME-1(%bx,%si)	# Greater than '9'?
+		ja ff.checkver.1
+		dec %si				# Next char
+		jnz ff.checkver
+		jmp ff.checklen			# All numbers in name, so
+						#  no version
+ff.checkver.1:	movzbw %es:DIR_NAMELEN(%bx),%cx
+		cmp %cx,%si			# Did we find any digits?
+		je ff.checkdot			# No
+		cmpb $';',%es:DIR_NAME-1(%bx,%si)	# Check for semicolon
+		jne ff.checkver.2
+		dec %si				# Skip semicolon
+		mov %si,%cx
+		mov %cl,%es:DIR_NAMELEN(%bx)	# Adjust length
+		jmp ff.checkdot
+ff.checkver.2:	mov %cx,%si			# Restore %si to end of string
+ff.checkdot:	cmpb $'.',%es:DIR_NAME-1(%bx,%si)	# Trailing dot?
+		jne ff.checklen			# No
+		decb %es:DIR_NAMELEN(%bx)	# Adjust length
+ff.checklen:	pop %si				# Restore
+		movzbw name_len,%cx		# Load length of name
+		cmp %cl,%es:DIR_NAMELEN(%bx)	# Does length match?
+		je ff.checkname			# Yes, check name
+ff.nextrec:	add %es:DIR_LEN(%bx),%bl	# Next record
+		adc $0,%bh
+		jmp ff.scan
+ff.nextblock:	subl $SECTOR_SIZE,rec_size	# Adjust size
+		jnc ff.load			# If subtract ok, keep going
+		ret				# End of file, so not found
+ff.checkname:	lea DIR_NAME(%bx),%di		# Address name in record
+		push %si			# Save
+		repe cmpsb			# Compare name
+		je ff.match			# We have a winner!
+		pop %si				# Restore
+		jmp ff.nextrec			# Keep looking.
+ff.match:	add $2,%sp			# Discard saved %si
+		clc				# Clear carry
+		ret
+
+#
+# Load DH sectors starting at LBA EAX into [EBX].
+#
+# Trashes: EAX
+#
+read:		push %es			# Save
+		push %bp
+		push %dx
+		push %cx
+		push %ebx
+		mov %bx,%bp			# Set destination address
+		and $0x000f,%bp
+		shr $4,%ebx
+		mov %bx,%es
+		xor %bx,%bx			# Set read bytes
+		mov %dh,%bl
+		shl $SECTOR_SHIFT,%bx		# 2048 bytes/sec
+		mov %ax,%cx			# Set LBA
+		shr $16,%eax
+		mov %ax,%dx
+read.retry:	mov $0x06,%ah			# BIOS device read
+		mov drive,%al
+		and $0x7f,%al
+		call twiddle			# Entertain the user
+		int $0x1b			# Call BIOS
+		jc read.fail			# Worked?
+		pop %ebx			# Restore
+		pop %cx
+		pop %dx
+		pop %bp
+		pop %es
+		ret				# Return
+read.fail:	cmp $ERROR_TIMEOUT,%ah		# Timeout?
+		je read.retry			# Yes, Retry.
+read.error:	mov %ah,%al			# Save error
+		mov $hex_error,%di		# Format it
+		call hex8			#  as hex
+		mov $msg_badread,%si		# Display Read error message
+		jmp error
+
+#
+# Output the "twiddle"
+#
+twiddle:	push %ax			# Save
+		push %bx			# Save
+		mov twiddle_index,%al		# Load index
+		mov $twiddle_chars,%bx		# Address table
+		inc %al				# Next
+		and $3,%al			#  char
+		mov %al,twiddle_index		# Save index for next call
+		xlat				# Get char
+		call putc			# Output it
+		pop %bx				# Restore
+		pop %ax				# Restore
+		ret
+
+#
+# Convert AL to hex, saving the result to [EDI].
+#
+hex8:		pushl %eax			# Save
+		shrb $0x4,%al			# Do upper
+		call hex8.1			#  4
+		popl %eax			# Restore
+hex8.1: 	andb $0xf,%al			# Get lower 4
+		cmpb $0xa,%al			# Convert
+		sbbb $0x69,%al			#  to hex
+		das				#  digit
+		orb $0x20,%al			# To lower case
+		mov %al,(%di)			# Save char
+		inc %di
+		ret				# (Recursive)
+
+#
+# BTX client to start btxldr
+#
+		.code32
+btx_client:	mov $(MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE-4), %esi
+						# %ds:(%esi) -> end
+						#  of boot[12] args
+		mov $(MEM_ARG_SIZE/4),%ecx	# Number of words to push
+		std				# Go backwards
+push_arg:	lodsl				# Read argument
+		push %eax			# Push it onto the stack
+		loop push_arg			# Push all of the arguments
+		cld				# In case anyone depends on this
+		pushl MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE # Entry point of
+						#  the loader
+		push %eax			# Emulate a near call
+		mov $0x1,%eax			# 'exec' system call
+		int $INT_SYS			# BTX system call
+btx_client_end:
+		.code16
+
+		.p2align 4
+#
+# Global descriptor table.
+#
+gdt:		.word 0x0,0x0,0x0,0x0			# Null entry
+		.word 0xffff,0x0000,0x9200,0x00cf	# SEL_SDATA
+		.word 0xffff,0x0000,0x9200,0x0000	# SEL_RDATA
+		.word 0xffff,LOAD_SEG<<4,0x9a00,0x00cf	# SEL_SCODE (32-bit)
+		.word 0xffff,LOAD_SEG<<4,0x9a00,0x008f	# SEL_SCODE16 (16-bit)
+gdt.1:
+#
+# Pseudo-descriptors.
+#
+gdtdesc:	.word gdt.1-gdt-1		# Limit
+		.long LOAD_SEG<<4 + gdt		# Base
+
+#
+# BOOT device
+#
+drive:		.byte 0
+cylinder:	.word 0
+
+#
+# State for searching dir
+#
+rec_lba:	.long 0x0			# LBA (adjusted for EA)
+rec_size:	.long 0x0			# File size
+name_len:	.byte 0x0			# Length of current name
+
+cursor:		.word 0
+twiddle_index:	.byte 0x0
+
+msg_welcome:	.asciz	"CD Loader 1.2\r\n\n"
+msg_bootinfo:	.asciz	"Building the boot loader arguments\r\n"
+msg_relocate:	.asciz	"Relocating the loader and the BTX\r\n"
+msg_jump:	.asciz	"Starting the BTX loader\r\n"
+msg_badread:	.ascii  "Read Error: 0x"
+hex_error:	.asciz	"00\r\n"
+msg_novd:	.asciz  "Could not find Primary Volume Descriptor\r\n"
+msg_lookup:	.asciz  "Looking up "
+msg_lookup2:	.asciz  "... "
+msg_lookupok:	.asciz  "Found\r\n"
+msg_lookupfail:	.asciz  "File not found\r\n"
+msg_load2big:	.asciz  "File too big\r\n"
+msg_failed:	.asciz	"Boot failed\r\n"
+twiddle_chars:	.ascii	"|/-\\"
+loader_paths:	.asciz  "/BOOT.PC98/LOADER"
+		.asciz	"/boot.pc98/loader"
+		.asciz  "/BOOT/LOADER"
+		.asciz	"/boot/loader"
+		.byte 0
+
+/* Boot signature */
+
+		.org SIG2_OFF,0x90
+
+		.word 0xaa55			# Magic number
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/pc98/cdboot/cdboot.s
--- a/head/sys/boot/pc98/cdboot/cdboot.s	Wed Jul 25 16:42:35 2012 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,811 +0,0 @@
-#
-# Copyright (c) 2006 TAKAHASHI Yoshihiro <nyan at FreeBSD.org>
-# Copyright (c) 2001 John Baldwin <jhb at FreeBSD.org>
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-#    notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-#    notice, this list of conditions and the following disclaimer in the
-#    documentation and/or other materials provided with the distribution.
-# 3. Neither the name of the author nor the names of any co-contributors
-#    may be used to endorse or promote products derived from this software
-#    without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-# SUCH DAMAGE.
-#
-
-# $FreeBSD$
-
-#
-# Basically, we first create a set of boot arguments to pass to the loaded
-# binary.  Then we attempt to load /boot/loader from the CD we were booted
-# off of. 
-#
-
-#
-# Memory locations.
-#
-		.set STACK_OFF,0x6000		# Stack offset
-		.set LOAD_SEG,0x0700		# Load segment
-		.set LOAD_SIZE,2048		# Load size
-		.set DAUA,0x0584		# DA/UA
-
-		.set MEM_PAGE_SIZE,0x1000	# memory page size, 4k
-		.set MEM_ARG,0x900		# Arguments at start
-		.set MEM_ARG_BTX,0xa100		# Where we move them to so the
-						#  BTX client can see them
-		.set MEM_ARG_SIZE,0x18		# Size of the arguments
-		.set MEM_BTX_ADDRESS,0x9000	# where BTX lives
-		.set MEM_BTX_ENTRY,0x9010	# where BTX starts to execute
-		.set MEM_BTX_OFFSET,MEM_PAGE_SIZE # offset of BTX in the loader
-		.set MEM_BTX_CLIENT,0xa000	# where BTX clients live
-#
-# PC98 machine type from sys/pc98/pc98/pc98_machdep.h
-#
-		.set MEM_SYS,		0xa100	# System common area segment
-		.set PC98_MACHINE_TYPE,	0x0620	# PC98 machine type
-		.set EPSON_ID,		0x0624	# EPSON machine id
-
-		.set M_NEC_PC98,	0x0001
-		.set M_EPSON_PC98,	0x0002
-		.set M_NOT_H98,		0x0010
-		.set M_H98,		0x0020
-		.set M_NOTE,		0x0040
-		.set M_NORMAL,		0x1000
-		.set M_8M,		0x8000
-#
-# Signature Constants
-#
-		.set SIG1_OFF,0x1fe		# Signature offset
-		.set SIG2_OFF,0x7fe		# Signature offset
-#
-# a.out header fields
-#
-		.set AOUT_TEXT,0x04		# text segment size
-		.set AOUT_DATA,0x08		# data segment size
-		.set AOUT_BSS,0x0c		# zero'd BSS size
-		.set AOUT_SYMBOLS,0x10		# symbol table
-		.set AOUT_ENTRY,0x14		# entry point
-		.set AOUT_HEADER,MEM_PAGE_SIZE	# size of the a.out header
-#
-# Flags for kargs->bootflags
-#
-		.set KARGS_FLAGS_CD,0x1		# flag to indicate booting from
-						#  CD loader
-#
-# Segment selectors.
-#
-		.set SEL_SDATA,0x8		# Supervisor data
-		.set SEL_RDATA,0x10		# Real mode data
-		.set SEL_SCODE,0x18		# PM-32 code
-		.set SEL_SCODE16,0x20		# PM-16 code
-#
-# BTX constants
-#
-		.set INT_SYS,0x30		# BTX syscall interrupt
-#
-# Constants for reading from the CD.
-#
-		.set ERROR_TIMEOUT,0x90		# BIOS timeout on read
-		.set NUM_RETRIES,3		# Num times to retry
-		.set SECTOR_SIZE,0x800		# size of a sector
-		.set SECTOR_SHIFT,11		# number of place to shift
-		.set BUFFER_LEN,0x100		# number of sectors in buffer
-		.set MAX_READ,0xf800		# max we can read at a time
-		.set MAX_READ_SEC,MAX_READ >> SECTOR_SHIFT
-		.set MEM_READ_BUFFER,0x9000	# buffer to read from CD
-		.set MEM_VOLDESC,MEM_READ_BUFFER # volume descriptor
-		.set MEM_DIR,MEM_VOLDESC+SECTOR_SIZE # Lookup buffer
-		.set VOLDESC_LBA,0x10		# LBA of vol descriptor
-		.set VD_PRIMARY,1		# Primary VD
-		.set VD_END,255			# VD Terminator
-		.set VD_ROOTDIR,156		# Offset of Root Dir Record
-		.set DIR_LEN,0			# Offset of Dir Record length
-		.set DIR_EA_LEN,1		# Offset of EA length
-		.set DIR_EXTENT,2		# Offset of 64-bit LBA
-		.set DIR_SIZE,10		# Offset of 64-bit length
-		.set DIR_NAMELEN,32		# Offset of 8-bit name len
-		.set DIR_NAME,33		# Offset of dir name
-
-#
-# Program start.
-#
-		.code16
-		.globl start
-
-start:		jmp main
-
-		.org 4
-		.ascii "IPL1   "
-
-main:		cld
-
-		/* Setup the stack */
-		xor %ax,%ax
-		mov %ax,%ss
-		mov $STACK_OFF,%sp
-
-		push %ecx
-
-		/* Setup graphic screen */
-		mov $0x42,%ah			# 640x400
-		mov $0xc0,%ch
-		int $0x18
-		mov $0x40,%ah			# graph on
-		int $0x18
-
-		/* Setup text screen */
-		mov $0x0a00,%ax			# 80x25
-		int $0x18
-		mov $0x0c,%ah			# text on
-		int $0x18
-		mov $0x13,%ah			# cursor home
-		xor %dx,%dx
-		int $0x18
-		mov $0x11,%ah			# cursor on
-		int $0x18
-
-		/* Setup keyboard */
-		mov $0x03,%ah
-		int $0x18
-
-		/* Transfer PC-9801 system common area */
-		xor %ax,%ax
-		mov %ax,%si
-		mov %ax,%ds
-		mov %ax,%di
-		mov $MEM_SYS,%ax
-		mov %ax,%es
-		mov $0x0600,%cx
-		rep
-		movsb
-
-		/* Transfer EPSON machine type */
-		mov $0xfd00,%ax
-		mov %ax,%ds
-		mov (0x804),%eax
-		and $0x00ffffff,%eax
-		mov %eax,%es:(EPSON_ID)
-
-		/* Set machine type to PC98_SYSTEM_PARAMETER */
-		call machine_check
-
-		/* Load cdboot */
-		xor %ax,%ax
-		mov %ax,%ds
-		mov $0x06,%ah		/* Read data */
-		mov (DAUA),%al		/* Read drive */
-		pop %ecx		/* cylinder */
-		xor %dx,%dx		/* head / sector */
-		mov $LOAD_SEG,%bx	/* Load address */
-		mov %bx,%es
-		xor %bp,%bp
-		mov $LOAD_SIZE,%bx	/* Load size */
-		int $0x1b
-		mov $msg_readerr,%si
-		jc error
-
-		/* Jump to cdboot */
-		ljmp $LOAD_SEG,$cdboot
-
-#
-# Set machine type to PC98_SYSTEM_PARAMETER.
-#
-machine_check:	xor %edx,%edx
-		mov %dx,%ds
-		mov $MEM_SYS,%ax
-		mov %ax,%es
-
-		/* Wait V-SYNC */
-vsync.1:	inb $0x60,%al
-		test $0x20,%al
-		jnz vsync.1
-vsync.2:	inb $0x60,%al
-		test $0x20,%al
-		jz vsync.2
-
-		/* ANK 'A' font */
-		xor %al,%al
-		outb %al,$0xa1
-		mov $0x41,%al
-		outb %al,$0xa3
-
-		/* Get 'A' font from CG window */
-		push %ds
-		mov $0xa400,%ax
-		mov %ax,%ds
-		xor %eax,%eax
-		xor %bx,%bx
-		mov $4,%cx
-font.1:		add (%bx),%eax
-		add $4,%bx
-		loop font.1
-		pop %ds
-		cmp $0x6efc58fc,%eax
-		jnz m_epson
-
-m_pc98:		or $M_NEC_PC98,%edx
-		mov $0x0458,%bx
-		mov (%bx),%al
-		test $0x80,%al
-		jz m_not_h98
-		or $M_H98,%edx
-		jmp 1f
-m_epson:	or $M_EPSON_PC98,%edx
-m_not_h98:	or $M_NOT_H98,%edx
-
-1:		inb $0x42,%al
-		test $0x20,%al
-		jz 1f
-		or $M_8M,%edx
-
-1:		mov $0x0400,%bx
-		mov (%bx),%al
-		test $0x80,%al
-		jz 1f
-		or $M_NOTE,%edx
-
-1:		mov $PC98_MACHINE_TYPE,%bx
-		mov %edx,%es:(%bx)
-		ret
-
-#
-# Print out the error message at [SI], wait for a keypress, and then
-# reboot the machine.
-#
-error:		call putstr
-		mov $msg_keypress,%si
-		call putstr
-		xor %ax,%ax			# Get keypress
-		int $0x18
-		xor %ax,%ax			# CPU reset
-		outb %al,$0xf0
-halt:		hlt
-		jmp halt			# Spin
-
-#
-# Display a null-terminated string at [SI].
-#
-# Trashes: AX, BX, CX, DX, SI, DI
-#
-putstr:		push %ds
-		push %es
-		mov %cs,%ax
-		mov %ax,%ds
-		mov $0xa000,%ax
-		mov %ax,%es
-		mov cursor,%di
-		mov $0x00e1,%bx			# Attribute
-		mov $160,%cx
-putstr.0:	lodsb
-		testb %al,%al
-		jz putstr.done
-		cmp $0x0d,%al
-		jz putstr.cr
-		cmp $0x0a,%al
-		jz putstr.lf
-		mov %bl,%es:0x2000(%di)
-		stosb
-		inc %di
-		jmp putstr.move
-putstr.cr:	xor %dx,%dx
-		mov %di,%ax
-		div %cx
-		sub %dx,%di
-		jmp putstr.move
-putstr.lf:	add %cx,%di
-putstr.move:	mov %di,%dx
-		mov $0x13,%ah			# Move cursor
-		int $0x18
-		jmp putstr.0
-putstr.done:	mov %di,cursor
-		pop %es
-		pop %ds
-		ret
-
-#
-# Display a single char at [AL], but don't move a cursor.
-#
-putc:		push %es
-		push %di
-		push %bx
-		mov $0xa000,%bx
-		mov %bx,%es
-		mov cursor,%di
-		mov $0xe1,%bl			# Attribute
-		mov %bl,%es:0x2000(%di)
-		stosb
-		pop %bx
-		pop %di
-		pop %es
-		ret
-
-msg_readerr:	.asciz "Read Error\r\n"
-msg_keypress:	.asciz "\r\nPress any key to reboot\r\n"
-
-/* Boot signature */
-
-		.org SIG1_OFF,0x90
-
-		.word 0xaa55			# Magic number
-
-#
-# cdboot
-#
-cdboot:		mov %cs,%ax
-		mov %ax,%ds
-		xor %ax,%ax
-		mov %ax,%es
-		mov %es:(DAUA),%al		# Save BIOS boot device
-		mov %al,drive
-		mov %cx,cylinder		# Save BIOS boot cylinder
-
-		mov $msg_welcome,%si		# %ds:(%si) -> welcome message
-		call putstr			# display the welcome message
-#
-# Setup the arguments that the loader is expecting from boot[12]
-#
-		mov $msg_bootinfo,%si		# %ds:(%si) -> boot args message
-		call putstr			# display the message
-		mov $MEM_ARG,%bx		# %ds:(%bx) -> boot args
-		mov %bx,%di			# %es:(%di) -> boot args
-		xor %eax,%eax			# zero %eax
-		mov $(MEM_ARG_SIZE/4),%cx	# Size of arguments in 32-bit
-						#  dwords
-		rep				# Clear the arguments
-		stosl				#  to zero
-		mov drive,%dl			# Store BIOS boot device
-		mov %dl,%es:0x4(%bx)		#  in kargs->bootdev
-		or $KARGS_FLAGS_CD,%es:0x8(%bx)	# kargs->bootflags |=
-						#  KARGS_FLAGS_CD
-#
-# Load Volume Descriptor
-#
-		mov $VOLDESC_LBA,%eax		# Set LBA of first VD
-load_vd:	push %eax			# Save %eax
-		mov $1,%dh			# One sector
-		mov $MEM_VOLDESC,%ebx		# Destination
-		call read			# Read it in
-		cmpb $VD_PRIMARY,%es:(%bx)	# Primary VD?
-		je have_vd			# Yes
-		pop %eax			# Prepare to
-		inc %eax			#  try next
-		cmpb $VD_END,%es:(%bx)		# Last VD?
-		jne load_vd			# No, read next
-		mov $msg_novd,%si		# No VD
-		jmp error			# Halt
-have_vd:					# Have Primary VD
-#
-# Try to look up the loader binary using the paths in the loader_paths
-# array.
-#
-		mov $loader_paths,%si		# Point to start of array
-lookup_path:	push %si			# Save file name pointer
-		call lookup			# Try to find file
-		pop %di				# Restore file name pointer
-		jnc lookup_found		# Found this file
-		push %es
-		mov %cs,%ax
-		mov %ax,%es
-		xor %al,%al			# Look for next
-		mov $0xffff,%cx			#  path name by
-		repnz				#  scanning for
-		scasb				#  nul char
-		pop %es
-		mov %di,%si			# Point %si at next path
-		mov (%si),%al			# Get first char of next path
-		or %al,%al			# Is it double nul?
-		jnz lookup_path			# No, try it.
-		mov $msg_failed,%si		# Failed message
-		jmp error			# Halt
-lookup_found:					# Found a loader file
-#
-# Load the binary into the buffer.  Due to real mode addressing limitations
-# we have to read it in 64k chunks.
-#
-		mov %es:DIR_SIZE(%bx),%eax	# Read file length
-		add $SECTOR_SIZE-1,%eax		# Convert length to sectors
-		shr $SECTOR_SHIFT,%eax
-		cmp $BUFFER_LEN,%eax
-		jbe load_sizeok
-		mov $msg_load2big,%si		# Error message
-		jmp error
-load_sizeok:	movzbw %al,%cx			# Num sectors to read
-		mov %es:DIR_EXTENT(%bx),%eax	# Load extent
-		xor %edx,%edx
-		mov %es:DIR_EA_LEN(%bx),%dl
-		add %edx,%eax			# Skip extended
-		mov $MEM_READ_BUFFER,%ebx	# Read into the buffer
-load_loop:	mov %cl,%dh
-		cmp $MAX_READ_SEC,%cl		# Truncate to max read size
-		jbe load_notrunc
-		mov $MAX_READ_SEC,%dh
-load_notrunc:	sub %dh,%cl			# Update count
-		push %eax			# Save
-		call read			# Read it in
-		pop %eax			# Restore
-		add $MAX_READ_SEC,%eax		# Update LBA
-		add $MAX_READ,%ebx		# Update dest addr
-		jcxz load_done			# Done?
-		jmp load_loop			# Keep going
-load_done:
-#
-# Turn on the A20 address line
-#
-		xor %ax,%ax			# Turn A20 on
-		outb %al,$0xf2
-		mov $0x02,%al
-		outb %al,$0xf6
-#
-# Relocate the loader and BTX using a very lazy protected mode
-#
-		mov $msg_relocate,%si		# Display the
-		call putstr			#  relocation message
-		mov %es:(MEM_READ_BUFFER+AOUT_ENTRY),%edi # %edi is the destination
-		mov $(MEM_READ_BUFFER+AOUT_HEADER),%esi	# %esi is
-						#  the start of the text
-						#  segment
-		mov %es:(MEM_READ_BUFFER+AOUT_TEXT),%ecx # %ecx = length of the text
-						#  segment
-		push %edi			# Save entry point for later
-		lgdt gdtdesc			# setup our own gdt
-		cli				# turn off interrupts
-		mov %cr0,%eax			# Turn on
-		or $0x1,%al			#  protected
-		mov %eax,%cr0			#  mode
-		ljmp $SEL_SCODE,$pm_start	# long jump to clear the
-						#  instruction pre-fetch queue
-		.code32
-pm_start:	mov $SEL_SDATA,%ax		# Initialize
-		mov %ax,%ds			#  %ds and
-		mov %ax,%es			#  %es to a flat selector
-		rep				# Relocate the
-		movsb				#  text segment
-		add $(MEM_PAGE_SIZE - 1),%edi	# pad %edi out to a new page
-		and $~(MEM_PAGE_SIZE - 1),%edi #  for the data segment
-		mov MEM_READ_BUFFER+AOUT_DATA,%ecx # size of the data segment
-		rep				# Relocate the
-		movsb				#  data segment
-		mov MEM_READ_BUFFER+AOUT_BSS,%ecx # size of the bss
-		xor %eax,%eax			# zero %eax
-		add $3,%cl			# round %ecx up to
-		shr $2,%ecx			#  a multiple of 4
-		rep				# zero the
-		stosl				#  bss
-		mov MEM_READ_BUFFER+AOUT_ENTRY,%esi # %esi -> relocated loader
-		add $MEM_BTX_OFFSET,%esi	# %esi -> BTX in the loader
-		mov $MEM_BTX_ADDRESS,%edi	# %edi -> where BTX needs to go
-		movzwl 0xa(%esi),%ecx		# %ecx -> length of BTX
-		rep				# Relocate
-		movsb				#  BTX
-		ljmp $SEL_SCODE16,$pm_16	# Jump to 16-bit PM
-		.code16
-pm_16:		mov $SEL_RDATA,%ax		# Initialize
-		mov %ax,%ds			#  %ds and
-		mov %ax,%es			#  %es to a real mode selector
-		mov %cr0,%eax			# Turn off
-		and $~0x1,%al			#  protected
-		mov %eax,%cr0			#  mode
-		ljmp $LOAD_SEG,$pm_end		# Long jump to clear the
-						#  instruction pre-fetch queue
-pm_end:		sti				# Turn interrupts back on now
-#
-# Copy the BTX client to MEM_BTX_CLIENT
-#
-		mov %cs,%ax
-		mov %ax,%ds
-		xor %ax,%ax
-		mov %ax,%es
-		mov $MEM_BTX_CLIENT,%di		# Prepare to relocate
-		mov $btx_client,%si		#  the simple btx client
-		mov $(btx_client_end-btx_client),%cx # length of btx client
-		rep				# Relocate the
-		movsb				#  simple BTX client
-#
-# Copy the boot[12] args to where the BTX client can see them
-#
-		xor %ax,%ax
-		mov %ax,%ds
-		mov $MEM_ARG,%si		# where the args are at now
-		mov $MEM_ARG_BTX,%di		# where the args are moving to
-		mov $(MEM_ARG_SIZE/4),%cx	# size of the arguments in longs
-		rep				# Relocate
-		movsl				#  the words
-#
-# Save the entry point so the client can get to it later on
-#
-		pop %eax			# Restore saved entry point
-		stosl				#  and add it to the end of
-						#  the arguments
-#
-# Now we just start up BTX and let it do the rest
-#
-		mov $msg_jump,%si		# Display the
-		call putstr			#  jump message
-		ljmp $0,$MEM_BTX_ENTRY		# Jump to the BTX entry point
-
-#
-# Lookup the file in the path at [SI] from the root directory.
-#
-# Trashes: All but BX
-# Returns: CF = 0 (success), BX = pointer to record
-#          CF = 1 (not found)
-#
-lookup:		mov $VD_ROOTDIR+MEM_VOLDESC,%bx	# Root directory record
-		push %bx
-		push %si
-		mov $msg_lookup,%si		# Display lookup message
-		call putstr
-		pop %si
-		push %si
-		call putstr
-		mov $msg_lookup2,%si
-		call putstr
-		pop %si
-		pop %bx
-lookup_dir:	lodsb				# Get first char of path
-		cmp $0,%al			# Are we done?
-		je lookup_done			# Yes
-		cmp $'/',%al			# Skip path separator.
-		je lookup_dir
-		dec %si				# Undo lodsb side effect
-		call find_file			# Lookup first path item
-		jnc lookup_dir			# Try next component
-		mov $msg_lookupfail,%si		# Not found message
-		push %bx
-		call putstr
-		pop %bx
-		stc				# Set carry
-		ret
-lookup_done:	mov $msg_lookupok,%si		# Success message
-		push %bx
-		call putstr
-		pop %bx
-		clc				# Clear carry
-		ret
-
-#
-# Lookup file at [SI] in directory whose record is at [BX].
-#
-# Trashes: All but returns
-# Returns: CF = 0 (success), BX = pointer to record, SI = next path item
-#          CF = 1 (not found), SI = preserved
-#
-find_file:	mov %es:DIR_EXTENT(%bx),%eax	# Load extent
-		xor %edx,%edx
-		mov %es:DIR_EA_LEN(%bx),%dl
-		add %edx,%eax			# Skip extended attributes
-		mov %eax,rec_lba		# Save LBA
-		mov %es:DIR_SIZE(%bx),%eax	# Save size
-		mov %eax,rec_size
-		xor %cl,%cl			# Zero length
-		push %si			# Save
-ff.namelen:	inc %cl				# Update length
-		lodsb				# Read char
-		cmp $0,%al			# Nul?
-		je ff.namedone			# Yes
-		cmp $'/',%al			# Path separator?
-		jnz ff.namelen			# No, keep going
-ff.namedone:	dec %cl				# Adjust length and save
-		mov %cl,name_len
-		pop %si				# Restore
-ff.load:	mov rec_lba,%eax		# Load LBA
-		mov $MEM_DIR,%ebx		# Address buffer
-		mov $1,%dh			# One sector
-		call read			# Read directory block
-		incl rec_lba			# Update LBA to next block
-ff.scan:	mov %ebx,%edx			# Check for EOF
-		sub $MEM_DIR,%edx
-		cmp %edx,rec_size
-		ja ff.scan.1
-		stc				# EOF reached
-		ret
-ff.scan.1:	cmpb $0,%es:DIR_LEN(%bx)	# Last record in block?
-		je ff.nextblock
-		push %si			# Save
-		movzbw %es:DIR_NAMELEN(%bx),%si	# Find end of string
-ff.checkver:	cmpb $'0',%es:DIR_NAME-1(%bx,%si)	# Less than '0'?
-		jb ff.checkver.1
-		cmpb $'9',%es:DIR_NAME-1(%bx,%si)	# Greater than '9'?
-		ja ff.checkver.1
-		dec %si				# Next char
-		jnz ff.checkver
-		jmp ff.checklen			# All numbers in name, so
-						#  no version
-ff.checkver.1:	movzbw %es:DIR_NAMELEN(%bx),%cx
-		cmp %cx,%si			# Did we find any digits?
-		je ff.checkdot			# No
-		cmpb $';',%es:DIR_NAME-1(%bx,%si)	# Check for semicolon
-		jne ff.checkver.2
-		dec %si				# Skip semicolon
-		mov %si,%cx
-		mov %cl,%es:DIR_NAMELEN(%bx)	# Adjust length
-		jmp ff.checkdot
-ff.checkver.2:	mov %cx,%si			# Restore %si to end of string
-ff.checkdot:	cmpb $'.',%es:DIR_NAME-1(%bx,%si)	# Trailing dot?
-		jne ff.checklen			# No
-		decb %es:DIR_NAMELEN(%bx)	# Adjust length
-ff.checklen:	pop %si				# Restore
-		movzbw name_len,%cx		# Load length of name
-		cmp %cl,%es:DIR_NAMELEN(%bx)	# Does length match?
-		je ff.checkname			# Yes, check name
-ff.nextrec:	add %es:DIR_LEN(%bx),%bl	# Next record
-		adc $0,%bh
-		jmp ff.scan
-ff.nextblock:	subl $SECTOR_SIZE,rec_size	# Adjust size
-		jnc ff.load			# If subtract ok, keep going
-		ret				# End of file, so not found
-ff.checkname:	lea DIR_NAME(%bx),%di		# Address name in record
-		push %si			# Save
-		repe cmpsb			# Compare name
-		je ff.match			# We have a winner!
-		pop %si				# Restore
-		jmp ff.nextrec			# Keep looking.
-ff.match:	add $2,%sp			# Discard saved %si
-		clc				# Clear carry
-		ret
-
-#
-# Load DH sectors starting at LBA EAX into [EBX].
-#
-# Trashes: EAX
-#
-read:		push %es			# Save
-		push %bp
-		push %dx
-		push %cx
-		push %ebx
-		mov %bx,%bp			# Set destination address
-		and $0x000f,%bp
-		shr $4,%ebx
-		mov %bx,%es
-		xor %bx,%bx			# Set read bytes
-		mov %dh,%bl
-		shl $SECTOR_SHIFT,%bx		# 2048 bytes/sec
-		mov %ax,%cx			# Set LBA
-		shr $16,%eax
-		mov %ax,%dx
-read.retry:	mov $0x06,%ah			# BIOS device read
-		mov drive,%al
-		and $0x7f,%al
-		call twiddle			# Entertain the user
-		int $0x1b			# Call BIOS
-		jc read.fail			# Worked?
-		pop %ebx			# Restore
-		pop %cx
-		pop %dx
-		pop %bp
-		pop %es
-		ret				# Return
-read.fail:	cmp $ERROR_TIMEOUT,%ah		# Timeout?
-		je read.retry			# Yes, Retry.
-read.error:	mov %ah,%al			# Save error
-		mov $hex_error,%di		# Format it
-		call hex8			#  as hex
-		mov $msg_badread,%si		# Display Read error message
-		jmp error
-
-#
-# Output the "twiddle"
-#
-twiddle:	push %ax			# Save
-		push %bx			# Save
-		mov twiddle_index,%al		# Load index
-		mov $twiddle_chars,%bx		# Address table
-		inc %al				# Next
-		and $3,%al			#  char
-		mov %al,twiddle_index		# Save index for next call
-		xlat				# Get char
-		call putc			# Output it
-		pop %bx				# Restore
-		pop %ax				# Restore
-		ret
-
-#
-# Convert AL to hex, saving the result to [EDI].
-#
-hex8:		pushl %eax			# Save
-		shrb $0x4,%al			# Do upper
-		call hex8.1			#  4
-		popl %eax			# Restore
-hex8.1: 	andb $0xf,%al			# Get lower 4
-		cmpb $0xa,%al			# Convert
-		sbbb $0x69,%al			#  to hex
-		das				#  digit
-		orb $0x20,%al			# To lower case
-		mov %al,(%di)			# Save char
-		inc %di
-		ret				# (Recursive)
-
-#
-# BTX client to start btxldr
-#
-		.code32
-btx_client:	mov $(MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE-4), %esi
-						# %ds:(%esi) -> end
-						#  of boot[12] args
-		mov $(MEM_ARG_SIZE/4),%ecx	# Number of words to push
-		std				# Go backwards
-push_arg:	lodsl				# Read argument
-		push %eax			# Push it onto the stack
-		loop push_arg			# Push all of the arguments
-		cld				# In case anyone depends on this
-		pushl MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE # Entry point of
-						#  the loader
-		push %eax			# Emulate a near call
-		mov $0x1,%eax			# 'exec' system call
-		int $INT_SYS			# BTX system call
-btx_client_end:
-		.code16
-
-		.p2align 4
-#
-# Global descriptor table.
-#
-gdt:		.word 0x0,0x0,0x0,0x0			# Null entry
-		.word 0xffff,0x0000,0x9200,0x00cf	# SEL_SDATA
-		.word 0xffff,0x0000,0x9200,0x0000	# SEL_RDATA
-		.word 0xffff,LOAD_SEG<<4,0x9a00,0x00cf	# SEL_SCODE (32-bit)
-		.word 0xffff,LOAD_SEG<<4,0x9a00,0x008f	# SEL_SCODE16 (16-bit)
-gdt.1:
-#
-# Pseudo-descriptors.
-#
-gdtdesc:	.word gdt.1-gdt-1		# Limit
-		.long LOAD_SEG<<4 + gdt		# Base
-
-#
-# BOOT device
-#
-drive:		.byte 0
-cylinder:	.word 0
-
-#
-# State for searching dir
-#
-rec_lba:	.long 0x0			# LBA (adjusted for EA)
-rec_size:	.long 0x0			# File size
-name_len:	.byte 0x0			# Length of current name
-
-cursor:		.word 0
-twiddle_index:	.byte 0x0
-
-msg_welcome:	.asciz	"CD Loader 1.2\r\n\n"
-msg_bootinfo:	.asciz	"Building the boot loader arguments\r\n"
-msg_relocate:	.asciz	"Relocating the loader and the BTX\r\n"
-msg_jump:	.asciz	"Starting the BTX loader\r\n"
-msg_badread:	.ascii  "Read Error: 0x"
-hex_error:	.asciz	"00\r\n"
-msg_novd:	.asciz  "Could not find Primary Volume Descriptor\r\n"
-msg_lookup:	.asciz  "Looking up "
-msg_lookup2:	.asciz  "... "
-msg_lookupok:	.asciz  "Found\r\n"
-msg_lookupfail:	.asciz  "File not found\r\n"
-msg_load2big:	.asciz  "File too big\r\n"
-msg_failed:	.asciz	"Boot failed\r\n"
-twiddle_chars:	.ascii	"|/-\\"
-loader_paths:	.asciz  "/BOOT.PC98/LOADER"
-		.asciz	"/boot.pc98/loader"
-		.asciz  "/BOOT/LOADER"
-		.asciz	"/boot/loader"
-		.byte 0
-
-/* Boot signature */
-
-		.org SIG2_OFF,0x90
-
-		.word 0xaa55			# Magic number
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/pc98/libpc98/Makefile
--- a/head/sys/boot/pc98/libpc98/Makefile	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/pc98/libpc98/Makefile	Wed Jul 25 16:45:04 2012 +0300
@@ -1,4 +1,4 @@
-# $FreeBSD$
+# $FreeBSD: head/sys/boot/pc98/libpc98/Makefile 235395 2012-05-13 11:34:05Z avg $
 #
 LIB=			pc98
 INTERNALLIB=
@@ -10,6 +10,8 @@
 	comconsole.c devicename.c elf32_freebsd.c \
 	i386_copy.c i386_module.c nullconsole.c pc98_sys.c pxe.c pxetramp.s \
 	time.c vidconsole.c
+.PATH:	${.CURDIR}/../../zfs
+SRCS+=	devicename_stubs.c
 
 # Enable PXE TFTP or NFS support, not both.
 .if defined(LOADER_TFTP_SUPPORT)
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/pc98/libpc98/biosdisk.c
--- a/head/sys/boot/pc98/libpc98/biosdisk.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/pc98/libpc98/biosdisk.c	Wed Jul 25 16:45:04 2012 +0300
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/boot/pc98/libpc98/biosdisk.c 235155 2012-05-09 08:05:50Z avg $");
 
 /*
  * BIOS disk device handling.
@@ -52,7 +52,6 @@
 #define BIOS_NUMDRIVES		0x475
 #define BIOSDISK_SECSIZE	512
 #define BUFSIZE			(1 * BIOSDISK_SECSIZE)
-#define	MAXBDDEV		MAXDEV
 
 #define DT_ATAPI		0x10		/* disk type for ATAPI floppies */
 #define WDMAJOR			0		/* major numbers for devices we frontend for */
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/pc98/loader/main.c
--- a/head/sys/boot/pc98/loader/main.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/pc98/loader/main.c	Wed Jul 25 16:45:04 2012 +0300
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/boot/pc98/loader/main.c 226746 2011-10-25 19:45:12Z jhb $");
+__FBSDID("$FreeBSD: head/sys/boot/pc98/loader/main.c 235264 2012-05-11 09:46:17Z avg $");
 
 /*
  * MD bootstrap main() and assorted miscellaneous
@@ -33,29 +33,25 @@
  */
 
 #include <stand.h>
+#include <stddef.h>
 #include <string.h>
 #include <machine/bootinfo.h>
 #include <sys/param.h>
 #include <sys/reboot.h>
 
 #include "bootstrap.h"
+#include "common/bootargs.h"
 #include "libi386/libi386.h"
 #include "libpc98/libpc98.h"
 #include "btxv86.h"
 
-#define	KARGS_FLAGS_CD		0x1
-#define	KARGS_FLAGS_PXE		0x2
+CTASSERT(sizeof(struct bootargs) == BOOTARGS_SIZE);
+CTASSERT(offsetof(struct bootargs, bootinfo) == BA_BOOTINFO);
+CTASSERT(offsetof(struct bootargs, bootflags) == BA_BOOTFLAGS);
+CTASSERT(offsetof(struct bootinfo, bi_size) == BI_SIZE);
 
 /* Arguments passed in from the boot1/boot2 loader */
-static struct 
-{
-    u_int32_t	howto;
-    u_int32_t	bootdev;
-    u_int32_t	bootflags;
-    u_int32_t	pxeinfo;
-    u_int32_t	res2;
-    u_int32_t	bootinfo;
-} *kargs;
+static struct bootargs *kargs;
 
 static u_int32_t	initial_howto;
 static u_int32_t	initial_bootdev;
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/powerpc/boot1.chrp/boot1.c
--- a/head/sys/boot/powerpc/boot1.chrp/boot1.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/powerpc/boot1.chrp/boot1.c	Wed Jul 25 16:45:04 2012 +0300
@@ -16,7 +16,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/boot/powerpc/boot1.chrp/boot1.c 231810 2012-02-16 03:27:38Z nwhitehorn $");
+__FBSDID("$FreeBSD: head/sys/boot/powerpc/boot1.chrp/boot1.c 235988 2012-05-25 09:36:39Z gleb $");
 
 #include <sys/param.h>
 #include <sys/dirent.h>
@@ -45,7 +45,6 @@
 static ofwh_t bootdev;
 
 static struct fs fs;
-static ino_t inomap;
 static char blkbuf[BSIZEMAX];
 static unsigned int fsblks;
 
@@ -492,7 +491,7 @@
 	Elf32_Ehdr eh;
 	Elf32_Phdr ph;
 	caddr_t p;
-	ino_t ino;
+	ufs_ino_t ino;
 	int i;
 
 	if ((ino = lookup(fname)) == 0) {
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/sparc64/Makefile
--- a/head/sys/boot/sparc64/Makefile	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/sparc64/Makefile	Wed Jul 25 16:45:04 2012 +0300
@@ -1,5 +1,5 @@
-# $FreeBSD$
+# $FreeBSD: head/sys/boot/sparc64/Makefile 234898 2012-05-01 17:16:01Z marius $
 
-SUBDIR=	boot1 loader
+SUBDIR=	boot1 loader zfsboot zfsloader
 
 .include <bsd.subdir.mk>
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/sparc64/boot1/Makefile
--- a/head/sys/boot/sparc64/boot1/Makefile	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/sparc64/boot1/Makefile	Wed Jul 25 16:45:04 2012 +0300
@@ -1,24 +1,25 @@
-# $FreeBSD$
+# $FreeBSD: head/sys/boot/sparc64/boot1/Makefile 235207 2012-05-09 19:08:54Z marius $
 
 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}
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/sparc64/boot1/boot1.c
--- a/head/sys/boot/sparc64/boot1/boot1.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/sparc64/boot1/boot1.c	Wed Jul 25 16:45:04 2012 +0300
@@ -16,15 +16,17 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/boot/sparc64/boot1/boot1.c 235988 2012-05-25 09:36:39Z gleb $");
 
 #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 uint32_t fs_off;
 
 int main(int ac, char **av);
+static void exit(int) __dead2;
+static void usage(void);
 
-static void exit(int) __dead2;
+#ifdef ZFSBOOT
+static void loadzfs(void);
+static int zbread(char *buf, off_t off, size_t bytes);
+#else
 static void load(const char *);
-static int dskread(void *, u_int64_t, int);
-
-static void usage(void);
+#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 @@
 	return ((u_char)*s1 - (u_char)*s2);
 }
 
-#include "ufsread.c"
-
 int
 main(int ac, char **av)
 {
@@ -335,14 +339,22 @@
 		}
 	}
 
-	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,31 +373,92 @@
 	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;
+	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)
 {
 	Elf64_Ehdr eh;
 	Elf64_Phdr ph;
 	caddr_t p;
-	ino_t ino;
+	ufs_ino_t ino;
 	int i;
 
 	if ((ino = lookup(fname)) == 0) {
@@ -421,6 +494,26 @@
 	(*(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)
 {
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/sparc64/loader/Makefile
--- a/head/sys/boot/sparc64/loader/Makefile	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/sparc64/loader/Makefile	Wed Jul 25 16:45:04 2012 +0300
@@ -1,10 +1,10 @@
-# $FreeBSD: head/sys/boot/sparc64/loader/Makefile 222472 2011-05-30 04:23:33Z julian $
+# $FreeBSD: head/sys/boot/sparc64/loader/Makefile 235364 2012-05-12 20:27:33Z avg $
 
 .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 @@
 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,12 @@
 .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
+LIBZFSBOOT=	${.OBJDIR}/../../zfs/libzfsboot.a
+.endif
 .if ${LOADER_GZIP_SUPPORT} == "yes"
 CFLAGS+=	-DLOADER_GZIP_SUPPORT
 .endif
@@ -47,7 +58,8 @@
 .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
 
@@ -72,11 +84,12 @@
 # where to get libstand from
 CFLAGS+=	-I${.CURDIR}/../../../../lib/libstand/
 
-DPADD=		${LIBFICL} ${LIBOFW} ${LIBSTAND}
-LDADD=		${LIBFICL} ${LIBOFW} -lstand
+DPADD=		${LIBFICL} ${LIBZFSBOOT} ${LIBOFW} ${LIBSTAND}
+LDADD=		${LIBFICL} ${LIBZFSBOOT} ${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} | \
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/sparc64/loader/main.c
--- a/head/sys/boot/sparc64/loader/main.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/sparc64/loader/main.c	Wed Jul 25 16:45:04 2012 +0300
@@ -33,7 +33,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/boot/sparc64/loader/main.c 223719 2011-07-02 11:14:54Z marius $");
+__FBSDID("$FreeBSD: head/sys/boot/sparc64/loader/main.c 236581 2012-06-04 20:56:40Z marius $");
 
 /*
  * FreeBSD/sparc64 kernel loader - machine dependent part
@@ -51,6 +51,10 @@
 #include <sys/linker.h>
 #include <sys/queue.h>
 #include <sys/types.h>
+#ifdef LOADER_ZFS_SUPPORT
+#include <sys/vtoc.h>
+#include "../zfs/libzfs.h"
+#endif
 
 #include <vm/vm.h>
 #include <machine/asi.h>
@@ -71,11 +75,7 @@
 #include "libofw.h"
 #include "dev_net.h"
 
-#ifndef CTASSERT
-#define	CTASSERT(x)		_CTASSERT(x, __LINE__)
-#define	_CTASSERT(x, y)		__CTASSERT(x, y)
-#define	__CTASSERT(x, y)	typedef char __assert ## y[(x) ? 1 : -1]
-#endif
+#define	MAXDEV	31
 
 extern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[];
 
@@ -141,6 +141,7 @@
 static vm_offset_t curkva = 0;
 static vm_offset_t heapva;
 
+static char bootpath[64];
 static phandle_t root;
 
 /*
@@ -154,6 +155,9 @@
 #ifdef LOADER_NET_SUPPORT
 	&netdev,
 #endif
+#ifdef LOADER_ZFS_SUPPORT
+	&zfs_dev,
+#endif
 	0
 };
 struct arch_switch archsw;
@@ -166,6 +170,7 @@
 	&sparc64_elf,
 	0
 };
+
 struct fs_ops *file_system[] = {
 #ifdef LOADER_UFS_SUPPORT
 	&ufs_fsops,
@@ -173,6 +178,9 @@
 #ifdef LOADER_CD9660_SUPPORT
 	&cd9660_fsops,
 #endif
+#ifdef LOADER_ZFS_SUPPORT
+	&zfs_fsops,
+#endif
 #ifdef LOADER_ZIP_SUPPORT
 	&zipfs_fsops,
 #endif
@@ -721,10 +729,58 @@
 		panic("%s: can't allocate TLB store", __func__);
 }
 
+#ifdef LOADER_ZFS_SUPPORT
+static void
+sparc64_zfs_probe(void)
+{
+	struct vtoc8 vtoc;
+	struct zfs_devdesc zfs_currdev;
+	char devname[32];
+	uint64_t guid;
+	int fd, part, unit;
+
+	/* Get the GUID of the ZFS pool on the boot device. */
+	guid = 0;
+	zfs_probe_dev(bootpath, &guid);
+
+	for (unit = 0; unit < MAXDEV; 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');
+			if (zfs_probe_dev(devname, NULL) == ENXIO)
+				break;
+		}
+	}
+
+	if (guid != 0) {
+		zfs_currdev.pool_guid = guid;
+		zfs_currdev.root_guid = 0;
+		zfs_currdev.d_dev = &zfs_dev;
+		zfs_currdev.d_type = zfs_currdev.d_dev->dv_type;
+		(void)strncpy(bootpath, zfs_fmtdev(&zfs_currdev),
+		    sizeof(bootpath) - 1);
+		bootpath[sizeof(bootpath) - 1] = '\0';
+	}
+}
+#endif /* LOADER_ZFS_SUPPORT */
+
 int
 main(int (*openfirm)(void *))
 {
-	char bootpath[64];
 	char compatible[32];
 	struct devsw **dp;
 
@@ -738,6 +794,9 @@
 	archsw.arch_copyout = ofw_copyout;
 	archsw.arch_readin = sparc64_readin;
 	archsw.arch_autoload = sparc64_autoload;
+#ifdef LOADER_ZFS_SUPPORT
+	archsw.arch_zfs_probe = sparc64_zfs_probe;
+#endif
 
 	if (init_heap() == (vm_offset_t)-1)
 		OF_exit();
@@ -756,14 +815,6 @@
 	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,11 +831,23 @@
 	 * needs to be altered.
 	 */
 	if (bootpath[strlen(bootpath) - 2] == ':' &&
-	    bootpath[strlen(bootpath) - 1] == 'f') {
+	    bootpath[strlen(bootpath) - 1] == 'f' &&
+	    strstr(bootpath, "cdrom") != NULL) {
 		bootpath[strlen(bootpath) - 1] = 'a';
 		printf("Boot path set to %s\n", bootpath);
 	}
 
+	/*
+	 * Initialize devices.
+	 */
+	for (dp = devsw; *dp != 0; dp++)
+		if ((*dp)->dv_init != 0)
+			(*dp)->dv_init();
+
+	/*
+	 * Now that sparc64_zfs_probe() might have altered bootpath,
+	 * export it.
+	 */
 	env_setenv("currdev", EV_VOLATILE, bootpath,
 	    ofw_setcurrdev, env_nounset);
 	env_setenv("loaddev", EV_VOLATILE, bootpath,
@@ -800,6 +863,18 @@
 	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
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/sparc64/zfsboot/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/boot/sparc64/zfsboot/Makefile	Wed Jul 25 16:45:04 2012 +0300
@@ -0,0 +1,9 @@
+# $FreeBSD: head/sys/boot/sparc64/zfsboot/Makefile 235207 2012-05-09 19:08:54Z marius $
+
+.PATH: ${.CURDIR}/../boot1
+
+PROGNAME=	zfsboot
+CFLAGS+=	-DZFSBOOT
+FILES=		zfsboot
+
+.include "${.CURDIR}/../boot1/Makefile"
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/sparc64/zfsloader/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/boot/sparc64/zfsloader/Makefile	Wed Jul 25 16:45:04 2012 +0300
@@ -0,0 +1,9 @@
+# $FreeBSD: head/sys/boot/sparc64/zfsloader/Makefile 234898 2012-05-01 17:16:01Z marius $
+
+.PATH: ${.CURDIR}/../loader
+
+PROG=		zfsloader
+NEWVERSWHAT=	"ZFS enabled bootstrap loader" sparc64
+LOADER_ZFS_SUPPORT=yes
+
+.include "${.CURDIR}/../loader/Makefile"
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/uboot/common/metadata.c
--- a/head/sys/boot/uboot/common/metadata.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/uboot/common/metadata.c	Wed Jul 25 16:45:04 2012 +0300
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/boot/uboot/common/metadata.c 233230 2012-03-20 13:08:57Z raj $");
+__FBSDID("$FreeBSD: head/sys/boot/uboot/common/metadata.c 235529 2012-05-17 04:04:48Z kientzle $");
 
 #include <stand.h>
 #include <sys/param.h>
@@ -42,7 +42,7 @@
 #include "glue.h"
 
 #if defined(LOADER_FDT_SUPPORT)
-extern int fdt_fixup(void);
+extern vm_offset_t fdt_fixup(void);
 #endif
 
 /*
@@ -72,6 +72,7 @@
 md_getboothowto(char *kargs)
 {
 	char	*cp;
+	char	*p;
 	int	howto;
 	int	active;
 	int	i;
@@ -132,10 +133,12 @@
 		if (getenv(howto_names[i].ev) != NULL)
 			howto |= howto_names[i].mask;
 	}
-	if (!strcmp(getenv("console"), "comconsole"))
-		howto |= RB_SERIAL;
-	if (!strcmp(getenv("console"), "nullconsole"))
-		howto |= RB_MUTE;
+	if ((p = getenv("console"))) {
+		if (!strcmp(p, "comconsole"))
+			howto |= RB_SERIAL;
+		if (!strcmp(p, "nullconsole"))
+			howto |= RB_MUTE;
+	}
 
 	return(howto);
 }
@@ -334,7 +337,7 @@
 #if defined(LOADER_FDT_SUPPORT)
 	/* Handle device tree blob */
 	dtbp = fdt_fixup();
-	if (dtbp != (vm_offset_t)NULL)
+	if (dtbp != 0)
 		file_addmetadata(kfp, MODINFOMD_DTBP, sizeof dtbp, &dtbp);
 	else
 		pager_output("WARNING! Trying to fire up the kernel, but no "
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/uboot/lib/api_public.h
--- a/head/sys/boot/uboot/lib/api_public.h	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/uboot/lib/api_public.h	Wed Jul 25 16:45:04 2012 +0300
@@ -48,7 +48,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/boot/uboot/lib/api_public.h 235609 2012-05-18 14:41:14Z gber $
  *
  * This file needs to be kept in sync with U-Boot reference:
  * http://www.denx.de/cgi-bin/gitweb.cgi?p=u-boot.git;a=blob;f=include/api_public.h
@@ -132,6 +132,7 @@
 #define	DT_STOR_SCSI	0x0020
 #define	DT_STOR_USB	0x0040
 #define	DT_STOR_MMC	0x0080
+#define	DT_STOR_NAND	0x0100
 
 #define	DEV_STA_CLOSED	0x0000		/* invalid, closed */
 #define	DEV_STA_OPEN	0x0001		/* open i.e. active */
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/uboot/lib/copy.c
--- a/head/sys/boot/uboot/lib/copy.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/uboot/lib/copy.c	Wed Jul 25 16:45:04 2012 +0300
@@ -26,35 +26,67 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/boot/uboot/lib/copy.c 235694 2012-05-20 18:07:35Z kientzle $");
 
 #include <stand.h>
+#include <stdint.h>
+
+#include "api_public.h"
+#include "glue.h"
 
 /*
  * MD primitives supporting placement of module data 
- *
- * XXX should check load address/size against memory top.
  */
 
+void *
+uboot_vm_translate(vm_offset_t o) {
+	struct sys_info *si;
+	static uintptr_t start = 0;
+	static size_t size = 0;
+	int i;
+
+	if (size == 0) {
+		if ((si = ub_get_sys_info()) == NULL)
+			panic("could not retrieve system info");
+
+		/* Find start/size of largest DRAM block. */
+		for (i = 0; i < si->mr_no; i++) {
+			if (si->mr[i].flags == MR_ATTR_DRAM
+			    && si->mr[i].size > size) {
+				start = si->mr[i].start;
+				size = si->mr[i].size;
+			}
+		}
+
+		if (size <= 0)
+			panic("No suitable DRAM?\n");
+		/*
+		printf("Loading into memory region 0x%08X-0x%08X (%d MiB)\n",
+		    start, start + size, size / 1024 / 1024);
+		*/
+	}
+	if (o > size)
+		panic("Address 0x%08jX bigger than size 0x%08X\n",
+		      (intmax_t)o, size);
+	return (void *)(start + o);
+}
+
 ssize_t
 uboot_copyin(const void *src, vm_offset_t dest, const size_t len)
 {
-
-	bcopy(src, (void *)dest, len);
+	bcopy(src, uboot_vm_translate(dest), len);
 	return (len);
 }
 
 ssize_t
 uboot_copyout(const vm_offset_t src, void *dest, const size_t len)
 {
-
-	bcopy((void *)src, dest, len);
+	bcopy(uboot_vm_translate(src), dest, len);
 	return (len);
 }
 
 ssize_t
 uboot_readin(const int fd, vm_offset_t dest, const size_t len)
 {
-
-	return (read(fd, (void *) dest, len));
+	return (read(fd, uboot_vm_translate(dest), len));
 }
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/uboot/lib/devicename.c
--- a/head/sys/boot/uboot/lib/devicename.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/uboot/lib/devicename.c	Wed Jul 25 16:45:04 2012 +0300
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/boot/uboot/lib/devicename.c 234860 2012-05-01 05:04:49Z kientzle $");
 
 #include <sys/disklabel.h>
 
@@ -131,6 +131,10 @@
 				    *(cp + 1) != ':') {
 					pnum = strtol(cp + 1, &cp, 10);
 					ptype = PTYPE_GPT;
+				} else if (*cp == 's' && *(cp + 1) &&
+				    *(cp + 1) != ':') {
+					pnum = strtol(cp + 1, &cp, 10);
+					ptype = PTYPE_MBR;
 				} else {
 					pnum = *cp - 'a';
 					ptype = PTYPE_BSDLABEL;
@@ -218,6 +222,9 @@
 			else if (dev->d_kind.disk.ptype == PTYPE_GPT)
 				cp += sprintf(cp, "p%i",
 				    dev->d_kind.disk.pnum);
+			else if (dev->d_kind.disk.ptype == PTYPE_MBR)
+				cp += sprintf(cp, "s%i",
+				    dev->d_kind.disk.pnum);
 		}
 
 		strcat(cp, ":");
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/uboot/lib/disk.c
--- a/head/sys/boot/uboot/lib/disk.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/uboot/lib/disk.c	Wed Jul 25 16:45:04 2012 +0300
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/boot/uboot/lib/disk.c 234860 2012-05-01 05:04:49Z kientzle $");
 
 #include <sys/param.h>
 #include <sys/endian.h>
@@ -398,6 +398,94 @@
 }
 
 static int
+stor_open_mbr(struct open_dev *od, struct uboot_devdesc *dev)
+{
+	char *buf = NULL;
+	struct dos_partition *dp;
+	int err, i, part;
+
+	od->od_nparts = 0;
+	od->od_partitions = NULL;
+
+	/* Block size must be at least 512 bytes. */
+	if (od->od_bsize < 512)
+		return (ENXIO);
+
+	/* Read MBR */
+	buf = malloc(od->od_bsize);
+	if (!buf) {
+		stor_printf("could not allocate memory for MBR\n");
+		return (ENOMEM);
+	}
+	err = stor_readdev(dev, 0, 1, buf);
+	if (err) {
+		stor_printf("MBR read error=%d\n", err);
+		err = EIO;
+		goto out;
+	}
+
+	/* Check the slice table magic. */
+	if (le16toh(*((uint16_t *)(buf + DOSMAGICOFFSET))) != DOSMAGIC) {
+		err = ENXIO;
+		goto out;
+	}
+
+	/* Save information about partitions. */
+	dp = (struct dos_partition *)(buf + DOSPARTOFF);
+	od->od_partitions = calloc(NDOSPART, sizeof(struct gpt_part));
+	if (!od->od_partitions) {
+		stor_printf("could not allocate memory for MBR partitions\n");
+		err = ENOMEM;
+		goto out;
+	}
+
+	part = 0;
+	for (i = 0; i < NDOSPART; i++) {
+		u_int32_t start = le32dec(&dp[i].dp_start);
+		u_int32_t size = le32dec(&dp[i].dp_size);
+		uuid_t *u = NULL;
+
+		/* Map MBR partition types to GPT partition types. */
+		switch (dp[i].dp_typ) {
+		case DOSPTYP_386BSD:
+			u = &freebsd_ufs;
+			break;
+		/* XXX Other types XXX */
+		}
+
+		if (u) {
+			od->od_partitions[part].gp_type = *u;
+			od->od_partitions[part].gp_index = i + 1;
+			od->od_partitions[part].gp_start = start;
+			od->od_partitions[part].gp_end = start + size;
+			part += 1;
+		}
+	}
+	od->od_nparts = part;
+
+	if (od->od_nparts == 0) {
+		err = EINVAL;
+		goto out;
+	}
+
+	dev->d_disk.ptype = PTYPE_MBR;
+
+	/* XXX Be smarter here? XXX */
+	if (dev->d_disk.pnum == 0)
+		dev->d_disk.pnum = od->od_partitions[0].gp_index;
+
+	for (i = 0; i < od->od_nparts; i++)
+		if (od->od_partitions[i].gp_index == dev->d_disk.pnum)
+			od->od_bstart = od->od_partitions[i].gp_start;
+
+out:
+	if (err && od->od_partitions)
+		free(od->od_partitions);
+	free(buf);
+	return (err);
+}
+
+static int
 stor_open_bsdlabel(struct open_dev *od, struct uboot_devdesc *dev)
 {
 	char *buf;
@@ -443,7 +531,7 @@
 	lbasize_t real_size;
 	int err, handle;
 
-	debugf("reading size=%d @ 0x%08x\n", size, (uint32_t)buf);
+	debugf("reading blk=%d size=%d @ 0x%08x\n", (int)blk, size, (uint32_t)buf);
 
 	handle = stor_info[dev->d_unit];
 	err = ub_dev_read(handle, buf, size, blk, &real_size);
@@ -495,7 +583,10 @@
 	od->od_bsize = di->di_stor.block_size;
 	od->od_bstart = 0;
 
-	if ((err = stor_open_gpt(od, dev)) != 0)
+	err = stor_open_gpt(od, dev);
+	if (err != 0)
+		err = stor_open_mbr(od, dev);
+	if (err != 0)
 		err = stor_open_bsdlabel(od, dev);
 
 	if (err != 0)
@@ -517,6 +608,8 @@
 	od = (struct open_dev *)dev->d_disk.data;
 	if (dev->d_disk.ptype == PTYPE_GPT && od->od_nparts != 0)
 		free(od->od_partitions);
+	if (dev->d_disk.ptype == PTYPE_MBR && od->od_nparts != 0)
+		free(od->od_partitions);
 
 	free(od);
 	dev->d_disk.data = NULL;
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/uboot/lib/elf_freebsd.c
--- a/head/sys/boot/uboot/lib/elf_freebsd.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/uboot/lib/elf_freebsd.c	Wed Jul 25 16:45:04 2012 +0300
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/boot/uboot/lib/elf_freebsd.c 235694 2012-05-20 18:07:35Z kientzle $");
 
 #include <sys/param.h>
 #include <sys/linker.h>
@@ -38,6 +38,7 @@
 #include <stand.h>
 
 #include "bootstrap.h"
+#include "libuboot.h"
 
 extern vm_offset_t md_load(char *, vm_offset_t *);
 
@@ -69,6 +70,7 @@
 	vm_offset_t mdp;
 	Elf_Ehdr *e;
 	int error;
+	void (*entry)(void *);
 
 	if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL)
 		return (EFTYPE);
@@ -78,11 +80,12 @@
 	if ((error = md_load(fp->f_args, &mdp)) != 0)
 		return (error);
 
-	printf("Kernel entry at 0x%x ...\n", e->e_entry);
+	entry = uboot_vm_translate(e->e_entry);
+	printf("Kernel entry at 0x%x...\n", (unsigned)entry);
 
 	dev_cleanup();
 
-	(*(void (*)())e->e_entry)((void *)mdp);
+	(*entry)((void *)mdp);
 	panic("exec returned");
 }
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/uboot/lib/glue.c
--- a/head/sys/boot/uboot/lib/glue.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/uboot/lib/glue.c	Wed Jul 25 16:45:04 2012 +0300
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/boot/uboot/lib/glue.c 233287 2012-03-21 20:53:47Z marius $");
+__FBSDID("$FreeBSD: head/sys/boot/uboot/lib/glue.c 235609 2012-05-18 14:41:14Z gber $");
 
 #include <sys/types.h>
 
@@ -407,6 +407,9 @@
 	if (type & DT_STOR_MMC)
 		return ("MMC");
 
+	if (type & DT_STOR_NAND)
+		return ("NAND");
+
 	return ("Unknown");
 }
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/uboot/lib/libuboot.h
--- a/head/sys/boot/uboot/lib/libuboot.h	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/uboot/lib/libuboot.h	Wed Jul 25 16:45:04 2012 +0300
@@ -24,7 +24,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/boot/uboot/lib/libuboot.h 235694 2012-05-20 18:07:35Z kientzle $
  */
 
 struct uboot_devdesc
@@ -45,6 +45,7 @@
 
 #define PTYPE_BSDLABEL	1
 #define PTYPE_GPT	2
+#define PTYPE_MBR	3
 
 /*
  * Default network packet alignment in memory
@@ -59,6 +60,7 @@
 extern struct netif_driver uboot_net;
 extern struct devsw uboot_storage;
 
+void *uboot_vm_translate(vm_offset_t);
 ssize_t	uboot_copyin(const void *src, vm_offset_t dest, const size_t len);
 ssize_t	uboot_copyout(const vm_offset_t src, void *dest, const size_t len);
 ssize_t	uboot_readin(const int fd, vm_offset_t dest, const size_t len);
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/userboot/libstand/Makefile
--- a/head/sys/boot/userboot/libstand/Makefile	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/userboot/libstand/Makefile	Wed Jul 25 16:45:04 2012 +0300
@@ -1,4 +1,4 @@
-# $FreeBSD: head/sys/boot/userboot/libstand/Makefile 229368 2012-01-03 07:14:01Z ed $
+# $FreeBSD: head/sys/boot/userboot/libstand/Makefile 237410 2012-06-21 21:47:08Z delphij $
 # Originally from	$NetBSD: Makefile,v 1.21 1997/10/26 22:08:38 lukem Exp $
 #
 # Notes:
@@ -42,7 +42,7 @@
 .endif
 
 # standalone components and stuff we have modified locally
-SRCS+=	zutil.h __main.c assert.c bcd.c bswap.c environment.c getopt.c gets.c \
+SRCS+=	gzguts.h zutil.h __main.c assert.c bcd.c bswap.c environment.c getopt.c gets.c \
 	globals.c pager.c printf.c strdup.c strerror.c strtol.c random.c \
 	sbrk.c twiddle.c zalloc.c zalloc_malloc.c
 
@@ -125,23 +125,28 @@
 # decompression functionality from libz
 .PATH: ${.CURDIR}/../../../../lib/libz
 CFLAGS+=-DHAVE_MEMCPY -I${.CURDIR}/../../../../lib/libz
-SRCS+=	adler32.c crc32.c libstand_zutil.h
+SRCS+=	adler32.c crc32.c libstand_zutil.h libstand_gzguts.h
 
 .for file in infback.c inffast.c inflate.c inftrees.c zutil.c
 SRCS+=	_${file}
 CLEANFILES+=	_${file}
 
 _${file}: ${file}
-	sed "s|zutil\.h|libstand_zutil.h|" ${.ALLSRC} > ${.TARGET}
+	sed -e "s|zutil\.h|libstand_zutil.h|" \
+	    -e "s|gzguts\.h|libstand_gzguts.h|" ${.ALLSRC} > ${.TARGET}
 .endfor
 
 # depend on stand.h being able to be included multiple times
-CLEANFILES+= libstand_zutil.h
-libstand_zutil.h: zutil.h
-	sed -e 's|<stddef.h>|"stand.h"|' \
+.for file in zutil.h gzguts.h
+CLEANFILES+= libstand_${file}
+libstand_${file}: ${file}
+	sed -e 's|<fcntl.h>|"stand.h"|' \
+	    -e 's|<stddef.h>|"stand.h"|' \
 	    -e 's|<string.h>|"stand.h"|' \
+	    -e 's|<stdio.h>|"stand.h"|' \
 	    -e 's|<stdlib.h>|"stand.h"|' \
 	    ${.ALLSRC} > ${.TARGET}
+.endfor
 
 # io routines
 SRCS+=	closeall.c dev.c ioctl.c nullfs.c stat.c \
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/zfs/devicename_stubs.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/boot/zfs/devicename_stubs.c	Wed Jul 25 16:45:04 2012 +0300
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 2012 Andriy Gapon <avg at FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/boot/zfs/devicename_stubs.c 235329 2012-05-12 09:03:30Z avg $");
+
+#include <stand.h>
+#include "libzfs.h"
+
+__attribute__((weak))
+int
+zfs_parsedev(struct zfs_devdesc *dev, const char *devspec, const char **path)
+{
+	return (EINVAL);
+}
+
+__attribute__((weak))
+char *
+zfs_fmtdev(void *vdev)
+{
+    static char	buf[128];
+
+    return (buf);
+}
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/zfs/libzfs.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/boot/zfs/libzfs.h	Wed Jul 25 16:45:04 2012 +0300
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 2012 Andriy Gapon <avg at FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/sys/boot/zfs/libzfs.h 235329 2012-05-12 09:03:30Z avg $
+ */
+
+#ifndef _BOOT_LIBZFS_H_
+#define _BOOT_LIBZFS_H_
+
+#define	ZFS_MAXNAMELEN	256
+
+/*
+ * ZFS fully-qualified device descriptor.
+ * Note, this must match the 'struct devdesc' declaration in bootstrap.h.
+ * Arch-specific device descriptors should be binary compatible with this
+ * structure if they are to support ZFS.
+ */
+struct zfs_devdesc
+{
+    struct devsw	*d_dev;
+    int			d_type;
+    int			d_unit;
+    void		*d_opendata;
+    uint64_t		pool_guid;
+    uint64_t		root_guid;
+};
+
+struct zfs_boot_args
+{
+    uint32_t		size;
+    uint32_t		reserved;
+    uint64_t		pool;
+    uint64_t		root;
+};
+
+int	zfs_parsedev(struct zfs_devdesc *dev, const char *devspec,
+		     const char **path);
+char	*zfs_fmtdev(void *vdev);
+int	zfs_probe_dev(const char *devname, uint64_t *pool_guid);
+
+extern struct devsw zfs_dev;
+extern struct fs_ops zfs_fsops;
+
+#endif /*_BOOT_LIBZFS_H_*/
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/zfs/zfs.c
--- a/head/sys/boot/zfs/zfs.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/zfs/zfs.c	Wed Jul 25 16:45:04 2012 +0300
@@ -23,11 +23,11 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *	$FreeBSD$
+ *	$FreeBSD: head/sys/boot/zfs/zfs.c 235394 2012-05-13 10:54:43Z avg $
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/boot/zfs/zfs.c 235394 2012-05-13 10:54:43Z avg $");
 
 /*
  *	Stand-alone file reading package.
@@ -43,10 +43,10 @@
 #include <stand.h>
 #include <bootstrap.h>
 
+#include "libzfs.h"
+
 #include "zfsimpl.c"
 
-#define	MAXBDDEV	31
-
 static int	zfs_open(const char *path, struct open_file *f);
 static int	zfs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
 static int	zfs_close(struct open_file *f);
@@ -85,35 +85,20 @@
 static int
 zfs_open(const char *upath, struct open_file *f)
 {
-	spa_t *spa = (spa_t *) f->f_devdata;
+	struct zfsmount *mount = (struct zfsmount *)f->f_devdata;
 	struct file *fp;
 	int rc;
 
 	if (f->f_dev != &zfs_dev)
 		return (EINVAL);
 
-	rc = zfs_mount_pool(spa);
-	if (rc)
-		return (rc);
-
 	/* allocate file system specific data structure */
 	fp = malloc(sizeof(struct file));
 	bzero(fp, sizeof(struct file));
 	f->f_fsdata = (void *)fp;
 
-	if (spa->spa_root_objset.os_type != DMU_OST_ZFS) {
-		printf("Unexpected object set type %llu\n",
-		    spa->spa_root_objset.os_type);
-		rc = EIO;
-		goto out;
-	}
-
-	rc = zfs_lookup(spa, upath, &fp->f_dnode);
-	if (rc)
-		goto out;
-
+	rc = zfs_lookup(mount, upath, &fp->f_dnode);
 	fp->f_seekp = 0;
-out:
 	if (rc) {
 		f->f_fsdata = NULL;
 		free(fp);
@@ -142,7 +127,7 @@
 static int
 zfs_read(struct open_file *f, void *start, size_t size, size_t *resid	/* out */)
 {
-	spa_t *spa = (spa_t *) f->f_devdata;
+	const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa;
 	struct file *fp = (struct file *)f->f_fsdata;
 	struct stat sb;
 	size_t n;
@@ -216,7 +201,7 @@
 static int
 zfs_stat(struct open_file *f, struct stat *sb)
 {
-	spa_t *spa = (spa_t *) f->f_devdata;
+	const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa;
 	struct file *fp = (struct file *)f->f_fsdata;
 
 	return (zfs_dnode_stat(spa, &fp->f_dnode, sb));
@@ -225,7 +210,7 @@
 static int
 zfs_readdir(struct open_file *f, struct dirent *d)
 {
-	spa_t *spa = (spa_t *) f->f_devdata;
+	const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa;
 	struct file *fp = (struct file *)f->f_fsdata;
 	mzap_ent_phys_t mze;
 	struct stat sb;
@@ -381,64 +366,31 @@
 	}
 }
 
-/*
- * Convert a pool guid to a 'unit number' suitable for use with zfs_dev_open.
- */
+static int
+zfs_dev_init(void)
+{
+	zfs_init();
+	if (archsw.arch_zfs_probe == NULL)
+		return (ENXIO);
+	archsw.arch_zfs_probe();
+	return (0);
+}
+
 int
-zfs_guid_to_unit(uint64_t guid)
+zfs_probe_dev(const char *devname, uint64_t *pool_guid)
 {
 	spa_t *spa;
-	int unit;
+	int fd;
+	int ret;
 
-	unit = 0;
-	STAILQ_FOREACH(spa, &zfs_pools, spa_link) {
-		if (spa->spa_guid == guid)
-			return unit;
-		unit++;
-	}
-	return (-1);
-}
-
-static int
-zfs_dev_init(void) 
-{
-	char devname[512];
-	int unit, slice;
-	int fd;
-
-	/*
-	 * Open all the disks we can find and see if we can reconstruct
-	 * ZFS pools from them. Bogusly assumes that the disks are named
-	 * diskN, diskNpM or diskNsM.
-	 */
-	zfs_init();
-	for (unit = 0; unit < MAXBDDEV; unit++) {
-		sprintf(devname, "disk%d:", unit);
-		fd = open(devname, O_RDONLY);
-		if (fd == -1)
-			continue;
-
-		/*
-		 * If we find a vdev, the zfs code will eat the fd, otherwise
-		 * we close it.
-		 */
-		if (vdev_probe(vdev_read, (void*) (uintptr_t) fd, 0))
-			close(fd);
-
-		for (slice = 1; slice <= 128; slice++) {
-			sprintf(devname, "disk%dp%d:", unit, slice);
-			fd = open(devname, O_RDONLY);
-			if (fd == -1) {
-				sprintf(devname, "disk%ds%d:", unit, slice);
-				fd = open(devname, O_RDONLY);
-				if (fd == -1)
-					continue;
-			}
-			if (vdev_probe(vdev_read, (void*) (uintptr_t) fd, 0))
-				close(fd);
-		}
-	}
-
+	fd = open(devname, O_RDONLY);
+	if (fd == -1)
+		return (ENXIO);
+	ret = vdev_probe(vdev_read, (void *)(uintptr_t)fd, &spa);
+	if (ret != 0)
+		close(fd);
+	else if (pool_guid != NULL)
+		*pool_guid = spa->spa_guid;
 	return (0);
 }
 
@@ -450,54 +402,52 @@
 {
 	spa_t *spa;
 	char line[80];
-	int unit;
 
 	if (verbose) {
 		spa_all_status();
 		return;
 	}
-	unit = 0;
 	STAILQ_FOREACH(spa, &zfs_pools, spa_link) {
-		sprintf(line, "    zfs%d:   %s\n", unit, spa->spa_name);
+		sprintf(line, "    zfs:%s\n", spa->spa_name);
 		pager_output(line);
-		unit++;
 	}
 }
 
 /*
  * Attempt to open the pool described by (dev) for use by (f).
  */
-static int 
+static int
 zfs_dev_open(struct open_file *f, ...)
 {
 	va_list		args;
-	struct devdesc	*dev;
-	int		unit, i;
+	struct zfs_devdesc	*dev;
+	struct zfsmount	*mount;
 	spa_t		*spa;
+	int		rv;
 
 	va_start(args, f);
-	dev = va_arg(args, struct devdesc*);
+	dev = va_arg(args, struct zfs_devdesc *);
 	va_end(args);
 
-	/*
-	 * We mostly ignore the stuff that devopen sends us. For now,
-	 * use the unit to find a pool - later we will override the
-	 * devname parsing so that we can name a pool and a fs within
-	 * the pool.
-	 */
-	unit = dev->d_unit;
-	
-	i = 0;
-	STAILQ_FOREACH(spa, &zfs_pools, spa_link) {
-		if (i == unit)
-			break;
-		i++;
+	spa = spa_find_by_guid(dev->pool_guid);
+	if (!spa)
+		return (ENXIO);
+	rv = zfs_spa_init(spa);
+	if (rv != 0)
+		return (rv);
+	mount = malloc(sizeof(*mount));
+	rv = zfs_mount(spa, dev->root_guid, mount);
+	if (rv != 0) {
+		free(mount);
+		return (rv);
 	}
-	if (!spa) {
-		return (ENXIO);
+	if (mount->objset.os_type != DMU_OST_ZFS) {
+		printf("Unexpected object set type %ju\n",
+		    (uintmax_t)mount->objset.os_type);
+		free(mount);
+		return (EIO);
 	}
-
-	f->f_devdata = spa;
+	f->f_devdata = mount;
 	free(dev);
 	return (0);
 }
@@ -506,6 +456,7 @@
 zfs_dev_close(struct open_file *f)
 {
 
+	free(f->f_devdata);
 	f->f_devdata = NULL;
 	return (0);
 }
@@ -518,13 +469,102 @@
 }
 
 struct devsw zfs_dev = {
-	.dv_name = "zfs", 
-	.dv_type = DEVT_ZFS, 
+	.dv_name = "zfs",
+	.dv_type = DEVT_ZFS,
 	.dv_init = zfs_dev_init,
-	.dv_strategy = zfs_dev_strategy, 
-	.dv_open = zfs_dev_open, 
-	.dv_close = zfs_dev_close, 
+	.dv_strategy = zfs_dev_strategy,
+	.dv_open = zfs_dev_open,
+	.dv_close = zfs_dev_close,
 	.dv_ioctl = noioctl,
 	.dv_print = zfs_dev_print,
 	.dv_cleanup = NULL
 };
+
+int
+zfs_parsedev(struct zfs_devdesc *dev, const char *devspec, const char **path)
+{
+	static char	rootname[ZFS_MAXNAMELEN];
+	static char	poolname[ZFS_MAXNAMELEN];
+	spa_t		*spa;
+	const char	*end;
+	const char	*np;
+	const char	*sep;
+	int		rv;
+
+	np = devspec;
+	if (*np != ':')
+		return (EINVAL);
+	np++;
+	end = strchr(np, ':');
+	if (end == NULL)
+		return (EINVAL);
+	sep = strchr(np, '/');
+	if (sep == NULL || sep >= end)
+		sep = end;
+	memcpy(poolname, np, sep - np);
+	poolname[sep - np] = '\0';
+	if (sep < end) {
+		sep++;
+		memcpy(rootname, sep, end - sep);
+		rootname[end - sep] = '\0';
+	}
+	else
+		rootname[0] = '\0';
+
+	spa = spa_find_by_name(poolname);
+	if (!spa)
+		return (ENXIO);
+	rv = zfs_spa_init(spa);
+	if (rv != 0)
+		return (rv);
+	dev->pool_guid = spa->spa_guid;
+	if (rootname[0] != '\0') {
+		rv = zfs_lookup_dataset(spa, rootname, &dev->root_guid);
+		if (rv != 0)
+			return (rv);
+	} else
+		dev->root_guid = 0;
+	if (path != NULL)
+		*path = (*end == '\0') ? end : end + 1;
+	dev->d_dev = &zfs_dev;
+	dev->d_type = zfs_dev.dv_type;
+	return (0);
+}
+
+char *
+zfs_fmtdev(void *vdev)
+{
+	static char		rootname[ZFS_MAXNAMELEN];
+	static char		buf[2 * ZFS_MAXNAMELEN + 8];
+	struct zfs_devdesc	*dev = (struct zfs_devdesc *)vdev;
+	spa_t			*spa;
+
+	buf[0] = '\0';
+	if (dev->d_type != DEVT_ZFS)
+		return (buf);
+
+	spa = spa_find_by_guid(dev->pool_guid);
+	if (spa == NULL) {
+		printf("ZFS: can't find pool by guid\n");
+		return (buf);
+	}
+	if (zfs_spa_init(spa) != 0) {
+		printf("ZFS: can't init pool\n");
+		return (buf);
+	}
+	if (dev->root_guid == 0 && zfs_get_root(spa, &dev->root_guid)) {
+		printf("ZFS: can't find root filesystem\n");
+		return (buf);
+	}
+	if (zfs_rlookup(spa, dev->root_guid, rootname)) {
+		printf("ZFS: can't find filesystem by guid\n");
+		return (buf);
+	}
+
+	if (rootname[0] == '\0')
+		sprintf(buf, "%s:%s:", dev->d_dev->dv_name, spa->spa_name);
+	else
+		sprintf(buf, "%s:%s/%s:", dev->d_dev->dv_name, spa->spa_name,
+		    rootname);
+	return (buf);
+}
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/boot/zfs/zfsimpl.c
--- a/head/sys/boot/zfs/zfsimpl.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/boot/zfs/zfsimpl.c	Wed Jul 25 16:45:04 2012 +0300
@@ -25,22 +25,37 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/boot/zfs/zfsimpl.c 228266 2011-12-04 21:29:56Z avg $");
+__FBSDID("$FreeBSD: head/sys/boot/zfs/zfsimpl.c 237001 2012-06-13 08:00:32Z mm $");
 
 /*
  *	Stand-alone ZFS file reader.
  */
 
 #include <sys/stat.h>
+#include <sys/stdint.h>
 
 #include "zfsimpl.h"
 #include "zfssubr.c"
 
+
+struct zfsmount {
+	const spa_t	*spa;
+	objset_phys_t	objset;
+	uint64_t	rootobj;
+};
+
 /*
  * List of all vdevs, chained through v_alllink.
  */
 static vdev_list_t zfs_vdevs;
 
+ /*
+ * List of ZFS features supported for read
+ */
+static const char *features_for_read[] = {
+	NULL
+};
+
 /*
  * List of all pools, chained through spa_link.
  */
@@ -55,7 +70,7 @@
 
 #define TEMP_SIZE	(1024 * 1024)
 
-static int zio_read(spa_t *spa, const blkptr_t *bp, void *buf);
+static int zio_read(const spa_t *spa, const blkptr_t *bp, void *buf);
 
 static void
 zfs_init(void)
@@ -190,6 +205,57 @@
 	return (EIO);
 }
 
+static int
+nvlist_check_features_for_read(const unsigned char *nvlist)
+{
+	const unsigned char *p, *pair;
+	int junk;
+	int encoded_size, decoded_size;
+	int rc;
+
+	rc = 0;
+
+	p = nvlist;
+	xdr_int(&p, &junk);
+	xdr_int(&p, &junk);
+
+	pair = p;
+	xdr_int(&p, &encoded_size);
+	xdr_int(&p, &decoded_size);
+	while (encoded_size && decoded_size) {
+		int namelen, pairtype;
+		const char *pairname;
+		int i, found;
+
+		found = 0;
+
+		xdr_int(&p, &namelen);
+		pairname = (const char*) p;
+		p += roundup(namelen, 4);
+		xdr_int(&p, &pairtype);
+
+		for (i = 0; features_for_read[i] != NULL; i++) {
+			if (!memcmp(pairname, features_for_read[i], namelen)) {
+				found = 1;
+				break;
+			}
+		}
+
+		if (!found) {
+			printf("ZFS: unsupported feature: %s\n", pairname);
+			rc = EIO;
+		}
+
+		p = pair + encoded_size;
+
+		pair = p;
+		xdr_int(&p, &encoded_size);
+		xdr_int(&p, &decoded_size);
+	}
+
+	return (rc);
+}
+
 /*
  * Return the next nvlist in an nvlist array.
  */
@@ -283,7 +349,7 @@
 		case DATA_TYPE_UINT64: {
 			uint64_t val;
 			xdr_uint64_t(&p, &val);
-			printf(" = 0x%llx\n", val);
+			printf(" = 0x%jx\n", (uintmax_t)val);
 			break;
 		}
 
@@ -343,7 +409,7 @@
 		psize = size;
 	}
 
-	/*printf("ZFS: reading %d bytes at 0x%llx to %p\n", psize, offset, buf);*/
+	/*printf("ZFS: reading %d bytes at 0x%jx to %p\n", psize, (uintmax_t)offset, buf);*/
 	rc = vdev->v_phys_read(vdev, vdev->v_read_priv, offset, buf, psize);
 	if (rc)
 		return (rc);
@@ -626,8 +692,6 @@
 	return (0);
 }
 
-#ifdef BOOT2
-
 static spa_t *
 spa_find_by_name(const char *name)
 {
@@ -640,8 +704,6 @@
 	return (0);
 }
 
-#endif
-
 static spa_t *
 spa_create(uint64_t guid)
 {
@@ -784,6 +846,7 @@
 	uint64_t is_log;
 	const char *pool_name;
 	const unsigned char *vdevs;
+	const unsigned char *features;
 	int i, rc, is_newer;
 	char *upbuf;
 	const struct uberblock *up;
@@ -818,12 +881,19 @@
 		return (EIO);
 	}
 
-	if (val > SPA_VERSION) {
+	if (!SPA_VERSION_IS_SUPPORTED(val)) {
 		printf("ZFS: unsupported ZFS version %u (should be %u)\n",
 		    (unsigned) val, (unsigned) SPA_VERSION);
 		return (EIO);
 	}
 
+	/* Check ZFS features for read */
+	if (nvlist_find(nvlist,
+			ZPOOL_CONFIG_FEATURES_FOR_READ,
+			DATA_TYPE_NVLIST, 0, &features) == 0
+	    && nvlist_check_features_for_read(features) != 0)
+		return (EIO);
+
 	if (nvlist_find(nvlist,
 			ZPOOL_CONFIG_POOL_STATE,
 			DATA_TYPE_UINT64, 0, &val)) {
@@ -977,7 +1047,7 @@
 }
 
 static int
-zio_read_gang(spa_t *spa, const blkptr_t *bp, void *buf)
+zio_read_gang(const spa_t *spa, const blkptr_t *bp, void *buf)
 {
 	blkptr_t gbh_bp;
 	zio_gbh_phys_t zio_gb;
@@ -1014,7 +1084,7 @@
 }
 
 static int
-zio_read(spa_t *spa, const blkptr_t *bp, void *buf)
+zio_read(const spa_t *spa, const blkptr_t *bp, void *buf)
 {
 	int cpfunc = BP_GET_COMPRESS(bp);
 	uint64_t align, size;
@@ -1074,7 +1144,7 @@
 }
 
 static int
-dnode_read(spa_t *spa, const dnode_phys_t *dnode, off_t offset, void *buf, size_t buflen)
+dnode_read(const spa_t *spa, const dnode_phys_t *dnode, off_t offset, void *buf, size_t buflen)
 {
 	int ibshift = dnode->dn_indblkshift - SPA_BLKPTRSHIFT;
 	int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT;
@@ -1137,7 +1207,7 @@
  * scratch buffer contains the directory contents.
  */
 static int
-mzap_lookup(spa_t *spa, const dnode_phys_t *dnode, const char *name, uint64_t *value)
+mzap_lookup(const dnode_phys_t *dnode, const char *name, uint64_t *value)
 {
 	const mzap_phys_t *mz;
 	const mzap_ent_phys_t *mze;
@@ -1218,7 +1288,7 @@
  * buffer contains the directory header.
  */
 static int
-fzap_lookup(spa_t *spa, const dnode_phys_t *dnode, const char *name, uint64_t *value)
+fzap_lookup(const spa_t *spa, const dnode_phys_t *dnode, const char *name, uint64_t *value)
 {
 	int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT;
 	zap_phys_t zh = *(zap_phys_t *) zap_scratch;
@@ -1296,7 +1366,7 @@
  * Lookup a name in a zap object and return its value as a uint64_t.
  */
 static int
-zap_lookup(spa_t *spa, const dnode_phys_t *dnode, const char *name, uint64_t *value)
+zap_lookup(const spa_t *spa, const dnode_phys_t *dnode, const char *name, uint64_t *value)
 {
 	int rc;
 	uint64_t zap_type;
@@ -1308,7 +1378,7 @@
 
 	zap_type = *(uint64_t *) zap_scratch;
 	if (zap_type == ZBT_MICRO)
-		return mzap_lookup(spa, dnode, name, value);
+		return mzap_lookup(dnode, name, value);
 	else if (zap_type == ZBT_HEADER)
 		return fzap_lookup(spa, dnode, name, value);
 	printf("ZFS: invalid zap_type=%d\n", (int)zap_type);
@@ -1322,7 +1392,7 @@
  * the directory contents.
  */
 static int
-mzap_list(spa_t *spa, const dnode_phys_t *dnode)
+mzap_list(const dnode_phys_t *dnode)
 {
 	const mzap_phys_t *mz;
 	const mzap_ent_phys_t *mze;
@@ -1340,7 +1410,7 @@
 	for (i = 0; i < chunks; i++) {
 		mze = &mz->mz_chunk[i];
 		if (mze->mze_name[0])
-			//printf("%-32s 0x%llx\n", mze->mze_name, mze->mze_value);
+			//printf("%-32s 0x%jx\n", mze->mze_name, (uintmax_t)mze->mze_value);
 			printf("%s\n", mze->mze_name);
 	}
 
@@ -1352,7 +1422,7 @@
  * the directory header.
  */
 static int
-fzap_list(spa_t *spa, const dnode_phys_t *dnode)
+fzap_list(const spa_t *spa, const dnode_phys_t *dnode)
 {
 	int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT;
 	zap_phys_t zh = *(zap_phys_t *) zap_scratch;
@@ -1391,7 +1461,7 @@
 			namelen = zc->l_entry.le_name_length;
 			if (namelen > sizeof(name))
 				namelen = sizeof(name);
-			
+
 			/*
 			 * Paste the name back together.
 			 */
@@ -1414,7 +1484,7 @@
 			 */
 			value = fzap_leaf_value(&zl, zc);
 
-			printf("%s 0x%llx\n", name, value);
+			printf("%s 0x%jx\n", name, (uintmax_t)value);
 		}
 	}
 
@@ -1425,7 +1495,7 @@
  * List a zap directory.
  */
 static int
-zap_list(spa_t *spa, const dnode_phys_t *dnode)
+zap_list(const spa_t *spa, const dnode_phys_t *dnode)
 {
 	uint64_t zap_type;
 	size_t size = dnode->dn_datablkszsec * 512;
@@ -1435,7 +1505,7 @@
 
 	zap_type = *(uint64_t *) zap_scratch;
 	if (zap_type == ZBT_MICRO)
-		return mzap_list(spa, dnode);
+		return mzap_list(dnode);
 	else
 		return fzap_list(spa, dnode);
 }
@@ -1443,7 +1513,7 @@
 #endif
 
 static int
-objset_get_dnode(spa_t *spa, const objset_phys_t *os, uint64_t objnum, dnode_phys_t *dnode)
+objset_get_dnode(const spa_t *spa, const objset_phys_t *os, uint64_t objnum, dnode_phys_t *dnode)
 {
 	off_t offset;
 
@@ -1452,24 +1522,278 @@
 		dnode, sizeof(dnode_phys_t));
 }
 
+static int
+mzap_rlookup(const spa_t *spa, const dnode_phys_t *dnode, char *name, uint64_t value)
+{
+	const mzap_phys_t *mz;
+	const mzap_ent_phys_t *mze;
+	size_t size;
+	int chunks, i;
+
+	/*
+	 * Microzap objects use exactly one block. Read the whole
+	 * thing.
+	 */
+	size = dnode->dn_datablkszsec * 512;
+
+	mz = (const mzap_phys_t *) zap_scratch;
+	chunks = size / MZAP_ENT_LEN - 1;
+
+	for (i = 0; i < chunks; i++) {
+		mze = &mz->mz_chunk[i];
+		if (value == mze->mze_value) {
+			strcpy(name, mze->mze_name);
+			return (0);
+		}
+	}
+
+	return (ENOENT);
+}
+
+static void
+fzap_name_copy(const zap_leaf_t *zl, const zap_leaf_chunk_t *zc, char *name)
+{
+	size_t namelen;
+	const zap_leaf_chunk_t *nc;
+	char *p;
+
+	namelen = zc->l_entry.le_name_length;
+
+	nc = &ZAP_LEAF_CHUNK(zl, zc->l_entry.le_name_chunk);
+	p = name;
+	while (namelen > 0) {
+		size_t len;
+		len = namelen;
+		if (len > ZAP_LEAF_ARRAY_BYTES)
+			len = ZAP_LEAF_ARRAY_BYTES;
+		memcpy(p, nc->l_array.la_array, len);
+		p += len;
+		namelen -= len;
+		nc = &ZAP_LEAF_CHUNK(zl, nc->l_array.la_next);
+	}
+
+	*p = '\0';
+}
+
+static int
+fzap_rlookup(const spa_t *spa, const dnode_phys_t *dnode, char *name, uint64_t value)
+{
+	int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT;
+	zap_phys_t zh = *(zap_phys_t *) zap_scratch;
+	fat_zap_t z;
+	uint64_t *ptrtbl;
+	uint64_t hash;
+	int rc;
+
+	if (zh.zap_magic != ZAP_MAGIC)
+		return (EIO);
+
+	z.zap_block_shift = ilog2(bsize);
+	z.zap_phys = (zap_phys_t *) zap_scratch;
+
+	/*
+	 * Figure out where the pointer table is and read it in if necessary.
+	 */
+	if (zh.zap_ptrtbl.zt_blk) {
+		rc = dnode_read(spa, dnode, zh.zap_ptrtbl.zt_blk * bsize,
+			       zap_scratch, bsize);
+		if (rc)
+			return (rc);
+		ptrtbl = (uint64_t *) zap_scratch;
+	} else {
+		ptrtbl = &ZAP_EMBEDDED_PTRTBL_ENT(&z, 0);
+	}
+
+	hash = zap_hash(zh.zap_salt, name);
+
+	zap_leaf_t zl;
+	zl.l_bs = z.zap_block_shift;
+
+	off_t off = ptrtbl[hash >> (64 - zh.zap_ptrtbl.zt_shift)] << zl.l_bs;
+	zap_leaf_chunk_t *zc;
+
+	rc = dnode_read(spa, dnode, off, zap_scratch, bsize);
+	if (rc)
+		return (rc);
+
+	zl.l_phys = (zap_leaf_phys_t *) zap_scratch;
+
+	/*
+	 * Make sure this chunk matches our hash.
+	 */
+	if (zl.l_phys->l_hdr.lh_prefix_len > 0
+	    && zl.l_phys->l_hdr.lh_prefix
+	    != hash >> (64 - zl.l_phys->l_hdr.lh_prefix_len))
+		return (ENOENT);
+
+	/*
+	 * Hash within the chunk to find our entry.
+	 */
+	int shift = (64 - ZAP_LEAF_HASH_SHIFT(&zl) - zl.l_phys->l_hdr.lh_prefix_len);
+	int h = (hash >> shift) & ((1 << ZAP_LEAF_HASH_SHIFT(&zl)) - 1);
+	h = zl.l_phys->l_hash[h];
+	if (h == 0xffff)
+		return (ENOENT);
+	zc = &ZAP_LEAF_CHUNK(&zl, h);
+	while (zc->l_entry.le_hash != hash) {
+		if (zc->l_entry.le_next == 0xffff) {
+			zc = 0;
+			break;
+		}
+		zc = &ZAP_LEAF_CHUNK(&zl, zc->l_entry.le_next);
+	}
+	if (fzap_leaf_value(&zl, zc) == value) {
+		fzap_name_copy(&zl, zc, name);
+		return (0);
+	}
+
+	return (ENOENT);
+}
+
+static int
+zap_rlookup(const spa_t *spa, const dnode_phys_t *dnode, char *name, uint64_t value)
+{
+	int rc;
+	uint64_t zap_type;
+	size_t size = dnode->dn_datablkszsec * 512;
+
+	rc = dnode_read(spa, dnode, 0, zap_scratch, size);
+	if (rc)
+		return (rc);
+
+	zap_type = *(uint64_t *) zap_scratch;
+	if (zap_type == ZBT_MICRO)
+		return mzap_rlookup(spa, dnode, name, value);
+	else
+		return fzap_rlookup(spa, dnode, name, value);
+}
+
+static int
+zfs_rlookup(const spa_t *spa, uint64_t objnum, char *result)
+{
+	char name[256];
+	char component[256];
+	uint64_t dir_obj, parent_obj, child_dir_zapobj;
+	dnode_phys_t child_dir_zap, dataset, dir, parent;
+	dsl_dir_phys_t *dd;
+	dsl_dataset_phys_t *ds;
+	char *p;
+	int len;
+
+	p = &name[sizeof(name) - 1];
+	*p = '\0';
+
+	if (objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset)) {
+		printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum);
+		return (EIO);
+	}
+	ds = (dsl_dataset_phys_t *)&dataset.dn_bonus;
+	dir_obj = ds->ds_dir_obj;
+
+	for (;;) {
+		if (objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir) != 0)
+			return (EIO);
+		dd = (dsl_dir_phys_t *)&dir.dn_bonus;
+
+		/* Actual loop condition. */
+		parent_obj  = dd->dd_parent_obj;
+		if (parent_obj == 0)
+			break;
+
+		if (objset_get_dnode(spa, &spa->spa_mos, parent_obj, &parent) != 0)
+			return (EIO);
+		dd = (dsl_dir_phys_t *)&parent.dn_bonus;
+		child_dir_zapobj = dd->dd_child_dir_zapobj;
+		if (objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, &child_dir_zap) != 0)
+			return (EIO);
+		if (zap_rlookup(spa, &child_dir_zap, component, dir_obj) != 0)
+			return (EIO);
+
+		len = strlen(component);
+		p -= len;
+		memcpy(p, component, len);
+		--p;
+		*p = '/';
+
+		/* Actual loop iteration. */
+		dir_obj = parent_obj;
+	}
+
+	if (*p != '\0')
+		++p;
+	strcpy(result, p);
+
+	return (0);
+}
+
+static int
+zfs_lookup_dataset(const spa_t *spa, const char *name, uint64_t *objnum)
+{
+	char element[256];
+	uint64_t dir_obj, child_dir_zapobj;
+	dnode_phys_t child_dir_zap, dir;
+	dsl_dir_phys_t *dd;
+	const char *p, *q;
+
+	if (objset_get_dnode(spa, &spa->spa_mos, DMU_POOL_DIRECTORY_OBJECT, &dir))
+		return (EIO);
+	if (zap_lookup(spa, &dir, DMU_POOL_ROOT_DATASET, &dir_obj))
+		return (EIO);
+
+	p = name;
+	for (;;) {
+		if (objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir))
+			return (EIO);
+		dd = (dsl_dir_phys_t *)&dir.dn_bonus;
+
+		while (*p == '/')
+			p++;
+		/* Actual loop condition #1. */
+		if (*p == '\0')
+			break;
+
+		q = strchr(p, '/');
+		if (q) {
+			memcpy(element, p, q - p);
+			element[q - p] = '\0';
+			p = q + 1;
+		} else {
+			strcpy(element, p);
+			p += strlen(p);
+		}
+
+		child_dir_zapobj = dd->dd_child_dir_zapobj;
+		if (objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, &child_dir_zap) != 0)
+			return (EIO);
+
+		/* Actual loop condition #2. */
+		if (zap_lookup(spa, &child_dir_zap, element, &dir_obj) != 0)
+			return (ENOENT);
+	}
+
+	*objnum = dd->dd_head_dataset_obj;
+	return (0);
+}
+
 /*
  * Find the object set given the object number of its dataset object
  * and return its details in *objset
  */
 static int
-zfs_mount_dataset(spa_t *spa, uint64_t objnum, objset_phys_t *objset)
+zfs_mount_dataset(const spa_t *spa, uint64_t objnum, objset_phys_t *objset)
 {
 	dnode_phys_t dataset;
 	dsl_dataset_phys_t *ds;
 
 	if (objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset)) {
-		printf("ZFS: can't find dataset %llu\n", objnum);
+		printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum);
 		return (EIO);
 	}
 
 	ds = (dsl_dataset_phys_t *) &dataset.dn_bonus;
 	if (zio_read(spa, &ds->ds_bp, objset)) {
-		printf("ZFS: can't read object set for dataset %llu\n", objnum);
+		printf("ZFS: can't read object set for dataset %ju\n",
+		    (uintmax_t)objnum);
 		return (EIO);
 	}
 
@@ -1481,11 +1805,13 @@
  * dataset if there is none and return its details in *objset
  */
 static int
-zfs_mount_root(spa_t *spa, objset_phys_t *objset)
+zfs_get_root(const spa_t *spa, uint64_t *objid)
 {
 	dnode_phys_t dir, propdir;
 	uint64_t props, bootfs, root;
 
+	*objid = 0;
+
 	/*
 	 * Start with the MOS directory object.
 	 */
@@ -1501,8 +1827,10 @@
 	     && objset_get_dnode(spa, &spa->spa_mos, props, &propdir) == 0
 	     && zap_lookup(spa, &propdir, "bootfs", &bootfs) == 0
 	     && bootfs != 0)
-		return zfs_mount_dataset(spa, bootfs, objset);
-
+	{
+		*objid = bootfs;
+		return (0);
+	}
 	/*
 	 * Lookup the root dataset directory
 	 */
@@ -1517,34 +1845,50 @@
 	 * to find the dataset object and from that the object set itself.
 	 */
 	dsl_dir_phys_t *dd = (dsl_dir_phys_t *) &dir.dn_bonus;
-	return zfs_mount_dataset(spa, dd->dd_head_dataset_obj, objset);
+	*objid = dd->dd_head_dataset_obj;
+	return (0);
 }
 
 static int
-zfs_mount_pool(spa_t *spa)
+zfs_mount(const spa_t *spa, uint64_t rootobj, struct zfsmount *mount)
 {
 
+	mount->spa = spa;
+
 	/*
-	 * Find the MOS and work our way in from there.
+	 * Find the root object set if not explicitly provided
 	 */
-	if (zio_read(spa, &spa->spa_uberblock.ub_rootbp, &spa->spa_mos)) {
-		printf("ZFS: can't read MOS\n");
+	if (rootobj == 0 && zfs_get_root(spa, &rootobj)) {
+		printf("ZFS: can't find root filesystem\n");
 		return (EIO);
 	}
 
-	/*
-	 * Find the root object set
-	 */
-	if (zfs_mount_root(spa, &spa->spa_root_objset)) {
-		printf("Can't find root filesystem - giving up\n");
+	if (zfs_mount_dataset(spa, rootobj, &mount->objset)) {
+		printf("ZFS: can't open root filesystem\n");
 		return (EIO);
 	}
 
+	mount->rootobj = rootobj;
+
 	return (0);
 }
 
 static int
-zfs_dnode_stat(spa_t *spa, dnode_phys_t *dn, struct stat *sb)
+zfs_spa_init(spa_t *spa)
+{
+
+	if (spa->spa_inited)
+		return (0);
+	if (zio_read(spa, &spa->spa_uberblock.ub_rootbp, &spa->spa_mos)) {
+		printf("ZFS: can't read MOS of pool %s\n", spa->spa_name);
+		return (EIO);
+	}
+	spa->spa_inited = 1;
+	return (0);
+}
+
+static int
+zfs_dnode_stat(const spa_t *spa, dnode_phys_t *dn, struct stat *sb)
 {
 
 	if (dn->dn_bonustype != DMU_OT_SA) {
@@ -1599,10 +1943,11 @@
  * Lookup a file and return its dnode.
  */
 static int
-zfs_lookup(spa_t *spa, const char *upath, dnode_phys_t *dnode)
+zfs_lookup(const struct zfsmount *mount, const char *upath, dnode_phys_t *dnode)
 {
 	int rc;
 	uint64_t objnum, rootnum, parentnum;
+	const spa_t *spa;
 	dnode_phys_t dn;
 	const char *p, *q;
 	char element[256];
@@ -1610,16 +1955,17 @@
 	int symlinks_followed = 0;
 	struct stat sb;
 
-	if (spa->spa_root_objset.os_type != DMU_OST_ZFS) {
-		printf("ZFS: unexpected object set type %llu\n",
-		       spa->spa_root_objset.os_type);
+	spa = mount->spa;
+	if (mount->objset.os_type != DMU_OST_ZFS) {
+		printf("ZFS: unexpected object set type %ju\n",
+		    (uintmax_t)mount->objset.os_type);
 		return (EIO);
 	}
 
 	/*
 	 * Get the root directory dnode.
 	 */
-	rc = objset_get_dnode(spa, &spa->spa_root_objset, MASTER_NODE_OBJ, &dn);
+	rc = objset_get_dnode(spa, &mount->objset, MASTER_NODE_OBJ, &dn);
 	if (rc)
 		return (rc);
 
@@ -1627,7 +1973,7 @@
 	if (rc)
 		return (rc);
 
-	rc = objset_get_dnode(spa, &spa->spa_root_objset, rootnum, &dn);
+	rc = objset_get_dnode(spa, &mount->objset, rootnum, &dn);
 	if (rc)
 		return (rc);
 
@@ -1660,7 +2006,7 @@
 			return (rc);
 		objnum = ZFS_DIRENT_OBJ(objnum);
 
-		rc = objset_get_dnode(spa, &spa->spa_root_objset, objnum, &dn);
+		rc = objset_get_dnode(spa, &mount->objset, objnum, &dn);
 		if (rc)
 			return (rc);
 
@@ -1702,7 +2048,7 @@
 				objnum = rootnum;
 			else
 				objnum = parentnum;
-			objset_get_dnode(spa, &spa->spa_root_objset, objnum, &dn);
+			objset_get_dnode(spa, &mount->objset, objnum, &dn);
 		}
 	}
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/ata/ata_all.c
--- a/head/sys/cam/ata/ata_all.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/ata/ata_all.c	Wed Jul 25 16:45:04 2012 +0300
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/cam/ata/ata_all.c 223019 2011-06-12 18:52:39Z mav $");
+__FBSDID("$FreeBSD: head/sys/cam/ata/ata_all.c 238393 2012-07-12 10:09:34Z brueffer $");
 
 #include <sys/param.h>
 
@@ -108,6 +108,16 @@
 	case 0x51: return ("CONFIGURE_STREAM");
 	case 0x60: return ("READ_FPDMA_QUEUED");
 	case 0x61: return ("WRITE_FPDMA_QUEUED");
+	case 0x67:
+		if (cmd->features == 0xec)
+			return ("SEP_ATTN IDENTIFY");
+		switch (cmd->lba_low) {
+		case 0x00: return ("SEP_ATTN READ BUFFER");
+		case 0x02: return ("SEP_ATTN RECEIVE DIAGNOSTIC RESULTS");
+		case 0x80: return ("SEP_ATTN WRITE BUFFER");
+		case 0x82: return ("SEP_ATTN SEND DIAGNOSTIC");
+		}
+		return ("SEP_ATTN");
 	case 0x70: return ("SEEK");
 	case 0x87: return ("CFA_TRANSLATE_SECTOR");
 	case 0x90: return ("EXECUTE_DEVICE_DIAGNOSTIC");
@@ -161,8 +171,8 @@
 	case 0xf2: return ("SECURITY_UNLOCK");
 	case 0xf3: return ("SECURITY_ERASE_PREPARE");
 	case 0xf4: return ("SECURITY_ERASE_UNIT");
-	case 0xf5: return ("SECURITY_FREE_LOCK");
-	case 0xf6: return ("SECURITY DISABLE PASSWORD");
+	case 0xf5: return ("SECURITY_FREEZE_LOCK");
+	case 0xf6: return ("SECURITY_DISABLE_PASSWORD");
 	case 0xf8: return ("READ_NATIVE_MAX_ADDRESS");
 	case 0xf9: return ("SET_MAX_ADDRESS");
 	}
@@ -286,6 +296,21 @@
 	printf(" device\n");
 }
 
+void
+semb_print_ident(struct sep_identify_data *ident_data)
+{
+	char vendor[9], product[17], revision[5], fw[5], in[7], ins[5];
+
+	cam_strvis(vendor, ident_data->vendor_id, 8, sizeof(vendor));
+	cam_strvis(product, ident_data->product_id, 16, sizeof(product));
+	cam_strvis(revision, ident_data->product_rev, 4, sizeof(revision));
+	cam_strvis(fw, ident_data->firmware_rev, 4, sizeof(fw));
+	cam_strvis(in, ident_data->interface_id, 6, sizeof(in));
+	cam_strvis(ins, ident_data->interface_rev, 4, sizeof(ins));
+	printf("<%s %s %s %s> SEMB %s %s device\n",
+	    vendor, product, revision, fw, in, ins);
+}
+
 uint32_t
 ata_logical_sector_size(struct ata_params *ident_data)
 {
@@ -334,7 +359,7 @@
 	ataio->cmd.lba_low = lba;
 	ataio->cmd.lba_mid = lba >> 8;
 	ataio->cmd.lba_high = lba >> 16;
-	ataio->cmd.device = 0x40 | ((lba >> 24) & 0x0f);
+	ataio->cmd.device = ATA_DEV_LBA | ((lba >> 24) & 0x0f);
 	ataio->cmd.sector_count = sector_count;
 }
 
@@ -359,7 +384,7 @@
 	ataio->cmd.lba_low = lba;
 	ataio->cmd.lba_mid = lba >> 8;
 	ataio->cmd.lba_high = lba >> 16;
-	ataio->cmd.device = 0x40;
+	ataio->cmd.device = ATA_DEV_LBA;
 	ataio->cmd.lba_low_exp = lba >> 24;
 	ataio->cmd.lba_mid_exp = lba >> 32;
 	ataio->cmd.lba_high_exp = lba >> 40;
@@ -379,7 +404,7 @@
 	ataio->cmd.lba_low = lba;
 	ataio->cmd.lba_mid = lba >> 8;
 	ataio->cmd.lba_high = lba >> 16;
-	ataio->cmd.device = 0x40;
+	ataio->cmd.device = ATA_DEV_LBA;
 	ataio->cmd.lba_low_exp = lba >> 24;
 	ataio->cmd.lba_mid_exp = lba >> 32;
 	ataio->cmd.lba_high_exp = lba >> 40;
@@ -695,3 +720,86 @@
 	}
         return (-1);
 }
+
+void
+semb_receive_diagnostic_results(struct ccb_ataio *ataio,
+    u_int32_t retries, void (*cbfcnp)(struct cam_periph *, union ccb*),
+    uint8_t tag_action, int pcv, uint8_t page_code,
+    uint8_t *data_ptr, uint16_t length, uint32_t timeout)
+{
+
+	length = min(length, 1020);
+	length = (length + 3) & ~3;
+	cam_fill_ataio(ataio,
+		      retries,
+		      cbfcnp,
+		      /*flags*/CAM_DIR_IN,
+		      tag_action,
+		      data_ptr,
+		      length,
+		      timeout);
+	ata_28bit_cmd(ataio, ATA_SEP_ATTN,
+	    pcv ? page_code : 0, 0x02, length / 4);
+}
+
+void
+semb_send_diagnostic(struct ccb_ataio *ataio,
+    u_int32_t retries, void (*cbfcnp)(struct cam_periph *, union ccb *),
+    uint8_t tag_action, uint8_t *data_ptr, uint16_t length, uint32_t timeout)
+{
+
+	length = min(length, 1020);
+	length = (length + 3) & ~3;
+	cam_fill_ataio(ataio,
+		      retries,
+		      cbfcnp,
+		      /*flags*/length ? CAM_DIR_OUT : CAM_DIR_NONE,
+		      tag_action,
+		      data_ptr,
+		      length,
+		      timeout);
+	ata_28bit_cmd(ataio, ATA_SEP_ATTN,
+	    length > 0 ? data_ptr[0] : 0, 0x82, length / 4);
+}
+
+void
+semb_read_buffer(struct ccb_ataio *ataio,
+    u_int32_t retries, void (*cbfcnp)(struct cam_periph *, union ccb*),
+    uint8_t tag_action, uint8_t page_code,
+    uint8_t *data_ptr, uint16_t length, uint32_t timeout)
+{
+
+	length = min(length, 1020);
+	length = (length + 3) & ~3;
+	cam_fill_ataio(ataio,
+		      retries,
+		      cbfcnp,
+		      /*flags*/CAM_DIR_IN,
+		      tag_action,
+		      data_ptr,
+		      length,
+		      timeout);
+	ata_28bit_cmd(ataio, ATA_SEP_ATTN,
+	    page_code, 0x00, length / 4);
+}
+
+void
+semb_write_buffer(struct ccb_ataio *ataio,
+    u_int32_t retries, void (*cbfcnp)(struct cam_periph *, union ccb *),
+    uint8_t tag_action, uint8_t *data_ptr, uint16_t length, uint32_t timeout)
+{
+
+	length = min(length, 1020);
+	length = (length + 3) & ~3;
+	cam_fill_ataio(ataio,
+		      retries,
+		      cbfcnp,
+		      /*flags*/length ? CAM_DIR_OUT : CAM_DIR_NONE,
+		      tag_action,
+		      data_ptr,
+		      length,
+		      timeout);
+	ata_28bit_cmd(ataio, ATA_SEP_ATTN,
+	    length > 0 ? data_ptr[0] : 0, 0x80, length / 4);
+}
+
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/ata/ata_all.h
--- a/head/sys/cam/ata/ata_all.h	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/ata/ata_all.h	Wed Jul 25 16:45:04 2012 +0300
@@ -23,7 +23,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: head/sys/cam/ata/ata_all.h 220886 2011-04-20 13:27:50Z mav $
+ * $FreeBSD: head/sys/cam/ata/ata_all.h 235897 2012-05-24 11:07:39Z mav $
  */
 
 #ifndef	CAM_ATA_ALL_H
@@ -83,6 +83,20 @@
 	u_int8_t	sector_count_exp;
 };
 
+struct sep_identify_data {
+	uint8_t		length;		/* Enclosure descriptor length */
+	uint8_t		subenc_id;	/* Sub-enclosure identifier */
+	uint8_t		logical_id[8];	/* Enclosure logical identifier (WWN) */
+	uint8_t		vendor_id[8];	/* Vendor identification string */
+	uint8_t		product_id[16];	/* Product identification string */
+	uint8_t		product_rev[4];	/* Product revision string */
+	uint8_t		channel_id;	/* Channel identifier */
+	uint8_t		firmware_rev[4];/* Firmware revision */
+	uint8_t		interface_id[6];/* Interface spec ("S-E-S "/"SAF-TE")*/
+	uint8_t		interface_rev[4];/* Interface spec revision */
+	uint8_t		vend_spec[11];	/* Vendor specific information */
+};
+
 int	ata_version(int ver);
 
 char *	ata_op_string(struct ata_cmd *cmd);
@@ -126,4 +140,26 @@
 int	ata_identify_match(caddr_t identbuffer, caddr_t table_entry);
 int	ata_static_identify_match(caddr_t identbuffer, caddr_t table_entry);
 
+void	semb_print_ident(struct sep_identify_data *ident_data);
+
+void semb_receive_diagnostic_results(struct ccb_ataio *ataio,
+	u_int32_t retries, void (*cbfcnp)(struct cam_periph *, union ccb*),
+	uint8_t tag_action, int pcv, uint8_t page_code,
+	uint8_t *data_ptr, uint16_t allocation_length, uint32_t timeout);
+
+void semb_send_diagnostic(struct ccb_ataio *ataio,
+	u_int32_t retries, void (*cbfcnp)(struct cam_periph *, union ccb *),
+	uint8_t tag_action, uint8_t *data_ptr, uint16_t param_list_length,
+	uint32_t timeout);
+
+void semb_read_buffer(struct ccb_ataio *ataio,
+	u_int32_t retries, void (*cbfcnp)(struct cam_periph *, union ccb*),
+	uint8_t tag_action, uint8_t page_code,
+	uint8_t *data_ptr, uint16_t allocation_length, uint32_t timeout);
+
+void semb_write_buffer(struct ccb_ataio *ataio,
+	u_int32_t retries, void (*cbfcnp)(struct cam_periph *, union ccb *),
+	uint8_t tag_action, uint8_t *data_ptr, uint16_t param_list_length,
+	uint32_t timeout);
+
 #endif
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/ata/ata_da.c
--- a/head/sys/cam/ata/ata_da.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/ata/ata_da.c	Wed Jul 25 16:45:04 2012 +0300
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/cam/ata/ata_da.c 234414 2012-04-18 08:55:26Z mav $");
+__FBSDID("$FreeBSD: head/sys/cam/ata/ata_da.c 238382 2012-07-11 23:22:09Z brueffer $");
 
 #include "opt_ada.h"
 #include "opt_ata.h"
@@ -368,9 +368,9 @@
 SYSCTL_INT(_kern_cam_ada, OID_AUTO, default_timeout, CTLFLAG_RW,
            &ada_default_timeout, 0, "Normal I/O timeout (in seconds)");
 TUNABLE_INT("kern.cam.ada.default_timeout", &ada_default_timeout);
-SYSCTL_INT(_kern_cam_ada, OID_AUTO, ada_send_ordered, CTLFLAG_RW,
+SYSCTL_INT(_kern_cam_ada, OID_AUTO, send_ordered, CTLFLAG_RW,
            &ada_send_ordered, 0, "Send Ordered Tags");
-TUNABLE_INT("kern.cam.ada.ada_send_ordered", &ada_send_ordered);
+TUNABLE_INT("kern.cam.ada.send_ordered", &ada_send_ordered);
 SYSCTL_INT(_kern_cam_ada, OID_AUTO, spindown_shutdown, CTLFLAG_RW,
            &ada_spindown_shutdown, 0, "Spin down upon shutdown");
 TUNABLE_INT("kern.cam.ada.spindown_shutdown", &ada_spindown_shutdown);
@@ -436,9 +436,8 @@
 	softc = (struct ada_softc *)periph->softc;
 	softc->flags |= ADA_FLAG_OPEN;
 
-	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
-	    ("adaopen: disk=%s%d (unit %d)\n", dp->d_name, dp->d_unit,
-	     periph->unit_number));
+	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH,
+	    ("adaopen\n"));
 
 	if ((softc->flags & ADA_FLAG_PACK_INVALID) != 0) {
 		/* Invalidate our pack information. */
@@ -469,6 +468,10 @@
 	}
 
 	softc = (struct ada_softc *)periph->softc;
+
+	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH,
+	    ("adaclose\n"));
+
 	/* We only sync the cache if the drive is capable of it. */
 	if ((softc->flags & ADA_FLAG_CAN_FLUSHCACHE) != 0 &&
 	    (softc->flags & ADA_FLAG_PACK_INVALID) == 0) {
@@ -487,7 +490,7 @@
 			ata_48bit_cmd(&ccb->ataio, ATA_FLUSHCACHE48, 0, 0, 0);
 		else
 			ata_28bit_cmd(&ccb->ataio, ATA_FLUSHCACHE, 0, 0, 0);
-		cam_periph_runccb(ccb, /*error_routine*/NULL, /*cam_flags*/0,
+		cam_periph_runccb(ccb, adaerror, /*cam_flags*/0,
 		    /*sense_flags*/0, softc->disk->d_devstat);
 
 		if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
@@ -542,6 +545,8 @@
 
 	cam_periph_lock(periph);
 
+	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("adastrategy(%p)\n", bp));
+
 	/*
 	 * If the device has been made invalid, error out
 	 */
@@ -579,6 +584,7 @@
 	struct	    disk *dp;
 	uint64_t    lba;
 	uint16_t    count;
+	int	    error = 0;
 
 	dp = arg;
 	periph = dp->d_drv1;
@@ -617,13 +623,16 @@
 		}
 		xpt_polled_action(&ccb);
 
-		if ((ccb.ataio.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+		error = cam_periph_error(&ccb,
+		    0, SF_NO_RECOVERY | SF_NO_RETRY, NULL);
+		if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0)
+			cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0,
+			    /*reduction*/0, /*timeout*/0, /*getcount_only*/0);
+		if (error != 0)
 			printf("Aborting dump due to I/O error.\n");
-			cam_periph_unlock(periph);
-			return(EIO);
-		}
+
 		cam_periph_unlock(periph);
-		return(0);
+		return (error);
 	}
 
 	if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) {
@@ -631,7 +640,7 @@
 
 		ccb.ccb_h.ccb_state = ADA_CCB_DUMP;
 		cam_fill_ataio(&ccb.ataio,
-				    1,
+				    0,
 				    adadone,
 				    CAM_DIR_NONE,
 				    0,
@@ -645,18 +654,16 @@
 			ata_28bit_cmd(&ccb.ataio, ATA_FLUSHCACHE, 0, 0, 0);
 		xpt_polled_action(&ccb);
 
-		if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
+		error = cam_periph_error(&ccb,
+		    0, SF_NO_RECOVERY | SF_NO_RETRY, NULL);
+		if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0)
+			cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0,
+			    /*reduction*/0, /*timeout*/0, /*getcount_only*/0);
+		if (error != 0)
 			xpt_print(periph->path, "Synchronize cache failed\n");
-
-		if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0)
-			cam_release_devq(ccb.ccb_h.path,
-					 /*relsim_flags*/0,
-					 /*reduction*/0,
-					 /*timeout*/0,
-					 /*getcount_only*/0);
 	}
 	cam_periph_unlock(periph);
-	return (0);
+	return (error);
 }
 
 static void
@@ -742,6 +749,7 @@
 adaasync(void *callback_arg, u_int32_t code,
 	struct cam_path *path, void *arg)
 {
+	struct ccb_getdev cgd;
 	struct cam_periph *periph;
 	struct ada_softc *softc;
 
@@ -776,11 +784,49 @@
 				"due to status 0x%x\n", status);
 		break;
 	}
+	case AC_GETDEV_CHANGED:
+	{
+		softc = (struct ada_softc *)periph->softc;
+		xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
+		cgd.ccb_h.func_code = XPT_GDEV_TYPE;
+		xpt_action((union ccb *)&cgd);
+
+		if ((cgd.ident_data.capabilities1 & ATA_SUPPORT_DMA) &&
+		    (cgd.inq_flags & SID_DMA))
+			softc->flags |= ADA_FLAG_CAN_DMA;
+		else
+			softc->flags &= ~ADA_FLAG_CAN_DMA;
+		if ((cgd.ident_data.satacapabilities & ATA_SUPPORT_NCQ) &&
+		    (cgd.inq_flags & SID_DMA) && (cgd.inq_flags & SID_CmdQue))
+			softc->flags |= ADA_FLAG_CAN_NCQ;
+		else
+			softc->flags &= ~ADA_FLAG_CAN_NCQ;
+		if ((cgd.ident_data.support_dsm & ATA_SUPPORT_DSM_TRIM) &&
+		    (cgd.inq_flags & SID_DMA))
+			softc->flags |= ADA_FLAG_CAN_TRIM;
+		else
+			softc->flags &= ~ADA_FLAG_CAN_TRIM;
+
+		cam_periph_async(periph, code, path, arg);
+		break;
+	}
+	case AC_ADVINFO_CHANGED:
+	{
+		uintptr_t buftype;
+
+		buftype = (uintptr_t)arg;
+		if (buftype == CDAI_TYPE_PHYS_PATH) {
+			struct ada_softc *softc;
+
+			softc = periph->softc;
+			disk_attr_changed(softc->disk, "GEOM::physpath",
+					  M_NOWAIT);
+		}
+		break;
+	}
 	case AC_SENT_BDR:
 	case AC_BUS_RESET:
 	{
-		struct ccb_getdev cgd;
-
 		softc = (struct ada_softc *)periph->softc;
 		cam_periph_async(periph, code, path, arg);
 		if (softc->state != ADA_STATE_NORMAL)
@@ -919,7 +965,7 @@
 	bioq_init(&softc->bio_queue);
 	bioq_init(&softc->trim_queue);
 
-	if (cgd->ident_data.capabilities1 & ATA_SUPPORT_DMA &&
+	if ((cgd->ident_data.capabilities1 & ATA_SUPPORT_DMA) &&
 	    (cgd->inq_flags & SID_DMA))
 		softc->flags |= ADA_FLAG_CAN_DMA;
 	if (cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48)
@@ -928,10 +974,11 @@
 		softc->flags |= ADA_FLAG_CAN_FLUSHCACHE;
 	if (cgd->ident_data.support.command1 & ATA_SUPPORT_POWERMGT)
 		softc->flags |= ADA_FLAG_CAN_POWERMGT;
-	if (cgd->ident_data.satacapabilities & ATA_SUPPORT_NCQ &&
+	if ((cgd->ident_data.satacapabilities & ATA_SUPPORT_NCQ) &&
 	    (cgd->inq_flags & SID_DMA) && (cgd->inq_flags & SID_CmdQue))
 		softc->flags |= ADA_FLAG_CAN_NCQ;
-	if (cgd->ident_data.support_dsm & ATA_SUPPORT_DSM_TRIM) {
+	if ((cgd->ident_data.support_dsm & ATA_SUPPORT_DSM_TRIM) &&
+	    (cgd->inq_flags & SID_DMA)) {
 		softc->flags |= ADA_FLAG_CAN_TRIM;
 		softc->trim_max_ranges = TRIM_MAX_RANGES;
 		if (cgd->ident_data.max_dsm_blocks != 0) {
@@ -1088,8 +1135,9 @@
 	 * them and the only alternative would be to
 	 * not attach the device on failure.
 	 */
-	xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE,
-			   adaasync, periph, periph->path);
+	xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE |
+	    AC_GETDEV_CHANGED | AC_ADVINFO_CHANGED,
+	    adaasync, periph, periph->path);
 
 	/*
 	 * Schedule a periodic event to occasionally send an
@@ -1126,6 +1174,8 @@
 	struct ada_softc *softc = (struct ada_softc *)periph->softc;
 	struct ccb_ataio *ataio = &start_ccb->ataio;
 
+	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("adastart\n"));
+
 	switch (softc->state) {
 	case ADA_STATE_NORMAL:
 	{
@@ -1134,7 +1184,7 @@
 
 		/* Execute immediate CCB if waiting. */
 		if (periph->immediate_priority <= periph->pinfo.priority) {
-			CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE,
+			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
 					("queuing for immediate ccb\n"));
 			start_ccb->ccb_h.ccb_state = ADA_CCB_WAITING;
 			SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
@@ -1426,6 +1476,9 @@
 
 	softc = (struct ada_softc *)periph->softc;
 	ataio = &done_ccb->ataio;
+
+	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("adadone\n"));
+
 	switch (ataio->ccb_h.ccb_state & ADA_CCB_TYPE_MASK) {
 	case ADA_CCB_BUFFER_IO:
 	case ADA_CCB_TRIM:
@@ -1665,6 +1718,7 @@
 {
 	struct cam_periph *periph;
 	struct ada_softc *softc;
+	int error;
 
 	TAILQ_FOREACH(periph, &adadriver.units, unit_links) {
 		union ccb ccb;
@@ -1688,7 +1742,7 @@
 
 		ccb.ccb_h.ccb_state = ADA_CCB_DUMP;
 		cam_fill_ataio(&ccb.ataio,
-				    1,
+				    0,
 				    adadone,
 				    CAM_DIR_NONE,
 				    0,
@@ -1702,15 +1756,13 @@
 			ata_28bit_cmd(&ccb.ataio, ATA_FLUSHCACHE, 0, 0, 0);
 		xpt_polled_action(&ccb);
 
-		if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
+		error = cam_periph_error(&ccb,
+		    0, SF_NO_RECOVERY | SF_NO_RETRY, NULL);
+		if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0)
+			cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0,
+			    /*reduction*/0, /*timeout*/0, /*getcount_only*/0);
+		if (error != 0)
 			xpt_print(periph->path, "Synchronize cache failed\n");
-
-		if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0)
-			cam_release_devq(ccb.ccb_h.path,
-					 /*relsim_flags*/0,
-					 /*reduction*/0,
-					 /*timeout*/0,
-					 /*getcount_only*/0);
 		cam_periph_unlock(periph);
 	}
 }
@@ -1720,6 +1772,7 @@
 {
 	struct cam_periph *periph;
 	struct ada_softc *softc;
+	int error;
 
 	TAILQ_FOREACH(periph, &adadriver.units, unit_links) {
 		union ccb ccb;
@@ -1744,7 +1797,7 @@
 
 		ccb.ccb_h.ccb_state = ADA_CCB_DUMP;
 		cam_fill_ataio(&ccb.ataio,
-				    1,
+				    0,
 				    adadone,
 				    CAM_DIR_NONE | flags,
 				    0,
@@ -1755,15 +1808,13 @@
 		ata_28bit_cmd(&ccb.ataio, cmd, 0, 0, 0);
 		xpt_polled_action(&ccb);
 
-		if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
+		error = cam_periph_error(&ccb,
+		    0, SF_NO_RECOVERY | SF_NO_RETRY, NULL);
+		if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0)
+			cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0,
+			    /*reduction*/0, /*timeout*/0, /*getcount_only*/0);
+		if (error != 0)
 			xpt_print(periph->path, "Spin-down disk failed\n");
-
-		if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0)
-			cam_release_devq(ccb.ccb_h.path,
-					 /*relsim_flags*/0,
-					 /*reduction*/0,
-					 /*timeout*/0,
-					 /*getcount_only*/0);
 		cam_periph_unlock(periph);
 	}
 }
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/ata/ata_pmp.c
--- a/head/sys/cam/ata/ata_pmp.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/ata/ata_pmp.c	Wed Jul 25 16:45:04 2012 +0300
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/cam/ata/ata_pmp.c 227309 2011-11-07 15:43:11Z ed $");
+__FBSDID("$FreeBSD: head/sys/cam/ata/ata_pmp.c 236602 2012-06-05 09:45:42Z mav $");
 
 #include <sys/param.h>
 
@@ -126,8 +126,13 @@
 #define	PMP_DEFAULT_RETRY	1
 #endif
 
+#ifndef	PMP_DEFAULT_HIDE_SPECIAL
+#define	PMP_DEFAULT_HIDE_SPECIAL	1
+#endif
+
 static int pmp_retry_count = PMP_DEFAULT_RETRY;
 static int pmp_default_timeout = PMP_DEFAULT_TIMEOUT;
+static int pmp_hide_special = PMP_DEFAULT_HIDE_SPECIAL;
 
 static SYSCTL_NODE(_kern_cam, OID_AUTO, pmp, CTLFLAG_RD, 0,
             "CAM Direct Access Disk driver");
@@ -137,6 +142,9 @@
 SYSCTL_INT(_kern_cam_pmp, OID_AUTO, default_timeout, CTLFLAG_RW,
            &pmp_default_timeout, 0, "Normal I/O timeout (in seconds)");
 TUNABLE_INT("kern.cam.pmp.default_timeout", &pmp_default_timeout);
+SYSCTL_INT(_kern_cam_pmp, OID_AUTO, hide_special, CTLFLAG_RW,
+           &pmp_hide_special, 0, "Hide extra ports");
+TUNABLE_INT("kern.cam.pmp.hide_special", &pmp_hide_special);
 
 static struct periph_driver pmpdriver =
 {
@@ -421,7 +429,9 @@
 
 	softc = (struct pmp_softc *)periph->softc;
 	ataio = &start_ccb->ataio;
-	
+
+	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("pmpstart\n"));
+
 	if (softc->restart) {
 		softc->restart = 0;
 		softc->state = min(softc->state, PMP_STATE_PRECONFIG);
@@ -552,7 +562,7 @@
 	softc = (struct pmp_softc *)periph->softc;
 	ataio = &done_ccb->ataio;
 
-	CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("pmpdone\n"));
+	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("pmpdone\n"));
 
 	priority = done_ccb->ccb_h.pinfo.priority;
 
@@ -583,23 +593,33 @@
 		    (ataio->res.lba_mid << 16) +
 		    (ataio->res.lba_low << 8) +
 		    ataio->res.sector_count;
-		/* This PMP declares 6 ports, while only 5 of them are real.
-		 * Port 5 is enclosure management bridge port, which has implementation
-		 * problems, causing probe faults. Hide it for now. */
-		if (softc->pm_pid == 0x37261095 && softc->pm_ports == 6)
-			softc->pm_ports = 5;
-		/* This PMP declares 7 ports, while only 5 of them are real.
-		 * Port 5 is some fake "Config  Disk" with 640 sectors size,
-		 * port 6 is enclosure management bridge port.
-		 * Both fake ports has implementation problems, causing
-		 * probe faults. Hide them for now. */
-		if (softc->pm_pid == 0x47261095 && softc->pm_ports == 7)
-			softc->pm_ports = 5;
-		/* These PMPs declare one more port then actually have,
-		 * for configuration purposes. Hide it for now. */
-		if (softc->pm_pid == 0x57231095 || softc->pm_pid == 0x57331095 ||
-		    softc->pm_pid == 0x57341095 || softc->pm_pid == 0x57441095)
-			softc->pm_ports--;
+		if (pmp_hide_special) {
+			/*
+			 * This PMP declares 6 ports, while only 5 of them
+			 * are real. Port 5 is a SEMB port, probing which
+			 * causes timeouts if external SEP is not connected
+			 * to PMP over I2C.
+			 */
+			if (softc->pm_pid == 0x37261095 && softc->pm_ports == 6)
+				softc->pm_ports = 5;
+
+			/*
+			 * This PMP declares 7 ports, while only 5 of them
+			 * are real. Port 5 is a fake "Config  Disk" with
+			 * 640 sectors size. Port 6 is a SEMB port.
+			 */
+			if (softc->pm_pid == 0x47261095 && softc->pm_ports == 7)
+				softc->pm_ports = 5;
+
+			/*
+			 * These PMPs have extra configuration port.
+			 */
+			if (softc->pm_pid == 0x57231095 ||
+			    softc->pm_pid == 0x57331095 ||
+			    softc->pm_pid == 0x57341095 ||
+			    softc->pm_pid == 0x57441095)
+				softc->pm_ports--;
+		}
 		printf("%s%d: %d fan-out ports\n",
 		    periph->periph_name, periph->unit_number,
 		    softc->pm_ports);
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/ata/ata_xpt.c
--- a/head/sys/cam/ata/ata_xpt.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/ata/ata_xpt.c	Wed Jul 25 16:45:04 2012 +0300
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/cam/ata/ata_xpt.c 230912 2012-02-02 14:17:58Z mav $");
+__FBSDID("$FreeBSD: head/sys/cam/ata/ata_xpt.c 236814 2012-06-09 13:07:44Z mav $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -65,6 +65,7 @@
 	struct scsi_inquiry_pattern inq_pat;
 	u_int8_t quirks;
 #define	CAM_QUIRK_MAXTAGS	0x01
+	u_int mintags;
 	u_int maxtags;
 };
 
@@ -93,6 +94,9 @@
 	PROBE_FULL_INQUIRY,
 	PROBE_PM_PID,
 	PROBE_PM_PRV,
+	PROBE_IDENTIFY_SES,
+	PROBE_IDENTIFY_SAFTE,
+	PROBE_DONE,
 	PROBE_INVALID
 } probe_action;
 
@@ -110,6 +114,9 @@
 	"PROBE_FULL_INQUIRY",
 	"PROBE_PM_PID",
 	"PROBE_PM_PRV",
+	"PROBE_IDENTIFY_SES",
+	"PROBE_IDENTIFY_SAFTE",
+	"PROBE_DONE",
 	"PROBE_INVALID"
 };
 
@@ -117,7 +124,7 @@
 do {									\
 	char **text;							\
 	text = probe_action_text;					\
-	CAM_DEBUG((softc)->periph->path, CAM_DEBUG_INFO,		\
+	CAM_DEBUG((softc)->periph->path, CAM_DEBUG_PROBE,		\
 	    ("Probe %s to %s\n", text[(softc)->action],			\
 	    text[(newaction)]));					\
 	(softc)->action = (newaction);					\
@@ -149,7 +156,7 @@
 		  T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED,
 		  /*vendor*/"*", /*product*/"*", /*revision*/"*"
 		},
-		/*quirks*/0, /*maxtags*/0
+		/*quirks*/0, /*mintags*/0, /*maxtags*/0
 	},
 };
 
@@ -160,9 +167,7 @@
 				      void *arg);
 static void	 probeschedule(struct cam_periph *probe_periph);
 static void	 probestart(struct cam_periph *periph, union ccb *start_ccb);
-//static void	 proberequestdefaultnegotiation(struct cam_periph *periph);
-//static int       proberequestbackoff(struct cam_periph *periph,
-//				     struct cam_ed *device);
+static void	 proberequestdefaultnegotiation(struct cam_periph *periph);
 static void	 probedone(struct cam_periph *periph, union ccb *done_ccb);
 static void	 probecleanup(struct cam_periph *periph);
 static void	 ata_find_quirk(struct cam_ed *device);
@@ -175,6 +180,7 @@
 		 ata_alloc_device(struct cam_eb *bus, struct cam_et *target,
 				   lun_id_t lun_id);
 static void	 ata_device_transport(struct cam_path *path);
+static void	 ata_get_transfer_settings(struct ccb_trans_settings *cts);
 static void	 ata_set_transfer_settings(struct ccb_trans_settings *cts,
 					    struct cam_ed *device,
 					    int async_update);
@@ -247,6 +253,8 @@
 	if (status != CAM_REQ_CMP) {
 		return (status);
 	}
+	CAM_DEBUG(periph->path, CAM_DEBUG_PROBE, ("Probe started\n"));
+
 	/*
 	 * Ensure nobody slip in until probe finish.
 	 */
@@ -266,7 +274,8 @@
 	ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs);
 
 	if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) ||
-	    periph->path->device->protocol == PROTO_SATAPM)
+	    periph->path->device->protocol == PROTO_SATAPM ||
+	    periph->path->device->protocol == PROTO_SEMB)
 		PROBE_SET_ACTION(softc, PROBE_RESET);
 	else
 		PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
@@ -300,7 +309,8 @@
 	if (softc->restart) {
 		softc->restart = 0;
 		if ((path->device->flags & CAM_DEV_UNCONFIGURED) ||
-		    path->device->protocol == PROTO_SATAPM)
+		    path->device->protocol == PROTO_SATAPM ||
+		    path->device->protocol == PROTO_SEMB)
 			softc->action = PROBE_RESET;
 		else
 			softc->action = PROBE_IDENTIFY;
@@ -406,6 +416,7 @@
 			path->device->inq_flags &= ~SID_DMA;
 		else
 			path->device->inq_flags |= SID_DMA;
+		xpt_async(AC_GETDEV_CHANGED, path, NULL);
 		cam_fill_ataio(ataio,
 		      1,
 		      probedone,
@@ -622,15 +633,36 @@
 		      10 * 1000);
 		ata_pm_read_cmd(ataio, 1, 15);
 		break;
-	case PROBE_INVALID:
-		CAM_DEBUG(path, CAM_DEBUG_INFO,
-		    ("probestart: invalid action state\n"));
+	case PROBE_IDENTIFY_SES:
+		cam_fill_ataio(ataio,
+		      1,
+		      probedone,
+		      /*flags*/CAM_DIR_IN,
+		      0,
+		      /*data_ptr*/(u_int8_t *)&softc->ident_data,
+		      /*dxfer_len*/sizeof(softc->ident_data),
+		      30 * 1000);
+		ata_28bit_cmd(ataio, ATA_SEP_ATTN, 0xEC, 0x02,
+		    sizeof(softc->ident_data) / 4);
+		break;
+	case PROBE_IDENTIFY_SAFTE:
+		cam_fill_ataio(ataio,
+		      1,
+		      probedone,
+		      /*flags*/CAM_DIR_IN,
+		      0,
+		      /*data_ptr*/(u_int8_t *)&softc->ident_data,
+		      /*dxfer_len*/sizeof(softc->ident_data),
+		      30 * 1000);
+		ata_28bit_cmd(ataio, ATA_SEP_ATTN, 0xEC, 0x00,
+		    sizeof(softc->ident_data) / 4);
+		break;
 	default:
-		break;
+		panic("probestart: invalid action state 0x%x\n", softc->action);
 	}
 	xpt_action(start_ccb);
 }
-#if 0
+
 static void
 proberequestdefaultnegotiation(struct cam_periph *periph)
 {
@@ -640,130 +672,29 @@
 	cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
 	cts.type = CTS_TYPE_USER_SETTINGS;
 	xpt_action((union ccb *)&cts);
-	if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+	if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
 		return;
-	}
+	cts.xport_specific.valid = 0;
 	cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
 	cts.type = CTS_TYPE_CURRENT_SETTINGS;
 	xpt_action((union ccb *)&cts);
 }
 
-/*
- * Backoff Negotiation Code- only pertinent for SPI devices.
- */
-static int
-proberequestbackoff(struct cam_periph *periph, struct cam_ed *device)
-{
-	struct ccb_trans_settings cts;
-	struct ccb_trans_settings_spi *spi;
-
-	memset(&cts, 0, sizeof (cts));
-	xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NONE);
-	cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
-	cts.type = CTS_TYPE_CURRENT_SETTINGS;
-	xpt_action((union ccb *)&cts);
-	if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
-		if (bootverbose) {
-			xpt_print(periph->path,
-			    "failed to get current device settings\n");
-		}
-		return (0);
-	}
-	if (cts.transport != XPORT_SPI) {
-		if (bootverbose) {
-			xpt_print(periph->path, "not SPI transport\n");
-		}
-		return (0);
-	}
-	spi = &cts.xport_specific.spi;
-
-	/*
-	 * We cannot renegotiate sync rate if we don't have one.
-	 */
-	if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) {
-		if (bootverbose) {
-			xpt_print(periph->path, "no sync rate known\n");
-		}
-		return (0);
-	}
-
-	/*
-	 * We'll assert that we don't have to touch PPR options- the
-	 * SIM will see what we do with period and offset and adjust
-	 * the PPR options as appropriate.
-	 */
-
-	/*
-	 * A sync rate with unknown or zero offset is nonsensical.
-	 * A sync period of zero means Async.
-	 */
-	if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0
-	 || spi->sync_offset == 0 || spi->sync_period == 0) {
-		if (bootverbose) {
-			xpt_print(periph->path, "no sync rate available\n");
-		}
-		return (0);
-	}
-
-	if (device->flags & CAM_DEV_DV_HIT_BOTTOM) {
-		CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
-		    ("hit async: giving up on DV\n"));
-		return (0);
-	}
-
-
-	/*
-	 * Jump sync_period up by one, but stop at 5MHz and fall back to Async.
-	 * We don't try to remember 'last' settings to see if the SIM actually
-	 * gets into the speed we want to set. We check on the SIM telling
-	 * us that a requested speed is bad, but otherwise don't try and
-	 * check the speed due to the asynchronous and handshake nature
-	 * of speed setting.
-	 */
-	spi->valid = CTS_SPI_VALID_SYNC_RATE | CTS_SPI_VALID_SYNC_OFFSET;
-	for (;;) {
-		spi->sync_period++;
-		if (spi->sync_period >= 0xf) {
-			spi->sync_period = 0;
-			spi->sync_offset = 0;
-			CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
-			    ("setting to async for DV\n"));
-			/*
-			 * Once we hit async, we don't want to try
-			 * any more settings.
-			 */
-			device->flags |= CAM_DEV_DV_HIT_BOTTOM;
-		} else if (bootverbose) {
-			CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
-			    ("DV: period 0x%x\n", spi->sync_period));
-			printf("setting period to 0x%x\n", spi->sync_period);
-		}
-		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
-		cts.type = CTS_TYPE_CURRENT_SETTINGS;
-		xpt_action((union ccb *)&cts);
-		if ((cts.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
-			break;
-		}
-		CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
-		    ("DV: failed to set period 0x%x\n", spi->sync_period));
-		if (spi->sync_period == 0) {
-			return (0);
-		}
-	}
-	return (1);
-}
-#endif
 static void
 probedone(struct cam_periph *periph, union ccb *done_ccb)
 {
 	struct ccb_trans_settings cts;
 	struct ata_params *ident_buf;
+	struct scsi_inquiry_data *inq_buf;
 	probe_softc *softc;
 	struct cam_path *path;
 	cam_status status;
 	u_int32_t  priority;
 	u_int caps;
-	int found = 1;
+	int changed = 1, found = 1;
+	static const uint8_t fake_device_id_hdr[8] =
+	    {0, SVPD_DEVICE_ID, 0, 12,
+	     SVPD_ID_CODESET_BINARY, SVPD_ID_TYPE_NAA, 0, 8};
 
 	CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probedone\n"));
 
@@ -771,14 +702,12 @@
 	path = done_ccb->ccb_h.path;
 	priority = done_ccb->ccb_h.pinfo.priority;
 	ident_buf = &path->device->ident_data;
+	inq_buf = &path->device->inq_data;
 
 	if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
-		if (softc->restart) {
-			if (bootverbose) {
-				cam_error_print(done_ccb,
-				    CAM_ESF_ALL, CAM_EPF_ALL);
-			}
-		} else if (cam_periph_error(done_ccb, 0, 0, NULL) == ERESTART)
+		if (cam_periph_error(done_ccb,
+		    0, softc->restart ? (SF_NO_RECOVERY | SF_NO_RETRY) : 0,
+		    NULL) == ERESTART)
 			return;
 		if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
 			/* Don't wedge the queue */
@@ -819,6 +748,18 @@
 		} else if (softc->action == PROBE_SETDMAAA &&
 		    status == CAM_ATA_STATUS_ERROR) {
 			goto noerror;
+
+		/*
+		 * SES and SAF-TE SEPs have different IDENTIFY commands,
+		 * but SATA specification doesn't tell how to identify them.
+		 * Until better way found, just try another if first fail.
+		 */
+		} else if (softc->action == PROBE_IDENTIFY_SES &&
+		    status == CAM_ATA_STATUS_ERROR) {
+			PROBE_SET_ACTION(softc, PROBE_IDENTIFY_SAFTE);
+			xpt_release_ccb(done_ccb);
+			xpt_schedule(periph, priority);
+			return;
 		}
 
 		/*
@@ -833,6 +774,7 @@
 		 */
 device_fail:	if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0)
 			xpt_async(AC_LOST_DEVICE, path, NULL);
+		PROBE_SET_ACTION(softc, PROBE_INVALID);
 		found = 0;
 		goto done;
 	}
@@ -844,8 +786,8 @@
 	{
 		int sign = (done_ccb->ataio.res.lba_high << 8) +
 		    done_ccb->ataio.res.lba_mid;
-		if (bootverbose)
-			xpt_print(path, "SIGNATURE: %04x\n", sign);
+		CAM_DEBUG(path, CAM_DEBUG_PROBE,
+		    ("SIGNATURE: %04x\n", sign));
 		if (sign == 0x0000 &&
 		    done_ccb->ccb_h.target_id != 15) {
 			path->device->protocol = PROTO_ATA;
@@ -862,6 +804,10 @@
 			xpt_action((union ccb *)&cts);
 			path->device->protocol = PROTO_SATAPM;
 			PROBE_SET_ACTION(softc, PROBE_PM_PID);
+		} else if (sign == 0xc33c &&
+		    done_ccb->ccb_h.target_id != 15) {
+			path->device->protocol = PROTO_SEMB;
+			PROBE_SET_ACTION(softc, PROBE_IDENTIFY_SES);
 		} else if (sign == 0xeb14 &&
 		    done_ccb->ccb_h.target_id != 15) {
 			path->device->protocol = PROTO_SCSI;
@@ -881,7 +827,6 @@
 	{
 		struct ccb_pathinq cpi;
 		int16_t *ptr;
-		int changed = 1;
 
 		ident_buf = &softc->ident_data;
 		for (ptr = (int16_t *)ident_buf;
@@ -936,6 +881,11 @@
 				path->device->serial_num = NULL;
 				path->device->serial_num_len = 0;
 			}
+			if (path->device->device_id != NULL) {
+				free(path->device->device_id, M_CAMXPT);
+				path->device->device_id = NULL;
+				path->device->device_id_len = 0;
+			}
 			path->device->serial_num =
 				(u_int8_t *)malloc((sizeof(ident_buf->serial) + 1),
 					   M_CAMXPT, M_NOWAIT);
@@ -948,11 +898,25 @@
 				path->device->serial_num_len =
 				    strlen(path->device->serial_num);
 			}
+			if (ident_buf->enabled.extension &
+			    ATA_SUPPORT_64BITWWN) {
+				path->device->device_id =
+				    malloc(16, M_CAMXPT, M_NOWAIT);
+				if (path->device->device_id != NULL) {
+					path->device->device_id_len = 16;
+					bcopy(&fake_device_id_hdr,
+					    path->device->device_id, 8);
+					bcopy(ident_buf->wwn,
+					    path->device->device_id + 8, 8);
+				}
+			}
 
 			path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID;
+			xpt_async(AC_GETDEV_CHANGED, path, NULL);
 		}
 		if (ident_buf->satacapabilities & ATA_SUPPORT_NCQ) {
-			path->device->mintags = path->device->maxtags =
+			path->device->mintags = 2;
+			path->device->maxtags =
 			    ATA_QUEUE_LEN(ident_buf->queue) + 1;
 		}
 		ata_find_quirk(path->device);
@@ -973,11 +937,11 @@
 				cts.xport_specific.sata.tags = path->device->maxtags;
 				cts.xport_specific.sata.valid = CTS_SATA_VALID_TAGS;
 				xpt_action((union ccb *)&cts);
-				/* Reconfigure queues for tagged queueing. */
-				xpt_start_tags(path);
 			}
 		}
 		ata_device_transport(path);
+		if (changed)
+			proberequestdefaultnegotiation(periph);
 		PROBE_SET_ACTION(softc, PROBE_SETMODE);
 		xpt_release_ccb(done_ccb);
 		xpt_schedule(periph, priority);
@@ -1088,15 +1052,14 @@
 			xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path,
 			    done_ccb);
 		}
+		PROBE_SET_ACTION(softc, PROBE_DONE);
 		break;
 	case PROBE_INQUIRY:
 	case PROBE_FULL_INQUIRY:
 	{
-		struct scsi_inquiry_data *inq_buf;
 		u_int8_t periph_qual, len;
 
 		path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID;
-		inq_buf = &path->device->inq_data;
 
 		periph_qual = SID_QUAL(inq_buf);
 
@@ -1131,6 +1094,7 @@
 			xpt_action(done_ccb);
 			xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, done_ccb);
 		}
+		PROBE_SET_ACTION(softc, PROBE_DONE);
 		break;
 	}
 	case PROBE_PM_PID:
@@ -1156,6 +1120,9 @@
 		snprintf(ident_buf->revision, sizeof(ident_buf->revision),
 		    "%04x", softc->pm_prv);
 		path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID;
+		ata_device_transport(path);
+		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED)
+			proberequestdefaultnegotiation(periph);
 		/* Set supported bits. */
 		bzero(&cts, sizeof(cts));
 		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
@@ -1199,12 +1166,56 @@
 			xpt_action(done_ccb);
 			xpt_async(AC_SCSI_AEN, done_ccb->ccb_h.path, done_ccb);
 		}
+		PROBE_SET_ACTION(softc, PROBE_DONE);
 		break;
-	case PROBE_INVALID:
-		CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_INFO,
-		    ("probedone: invalid action state\n"));
+	case PROBE_IDENTIFY_SES:
+	case PROBE_IDENTIFY_SAFTE:
+		if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) {
+			/* Check that it is the same device. */
+			if (bcmp(&softc->ident_data, ident_buf, 53)) {
+				/* Device changed. */
+				xpt_async(AC_LOST_DEVICE, path, NULL);
+			} else {
+				bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params));
+				changed = 0;
+			}
+		}
+		if (changed) {
+			bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params));
+			/* Clean up from previous instance of this device */
+			if (path->device->device_id != NULL) {
+				free(path->device->device_id, M_CAMXPT);
+				path->device->device_id = NULL;
+				path->device->device_id_len = 0;
+			}
+			path->device->device_id =
+			    malloc(16, M_CAMXPT, M_NOWAIT);
+			if (path->device->device_id != NULL) {
+				path->device->device_id_len = 16;
+				bcopy(&fake_device_id_hdr,
+				    path->device->device_id, 8);
+				bcopy(((uint8_t*)ident_buf) + 2,
+				    path->device->device_id + 8, 8);
+			}
+
+			path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID;
+		}
+		ata_device_transport(path);
+		if (changed)
+			proberequestdefaultnegotiation(periph);
+
+		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
+			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
+			xpt_acquire_device(path->device);
+			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
+			xpt_action(done_ccb);
+			xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path,
+			    done_ccb);
+		}
+		PROBE_SET_ACTION(softc, PROBE_DONE);
+		break;
 	default:
-		break;
+		panic("probedone: invalid action state 0x%x\n", softc->action);
 	}
 done:
 	if (softc->restart) {
@@ -1214,15 +1225,16 @@
 		return;
 	}
 	xpt_release_ccb(done_ccb);
+	CAM_DEBUG(periph->path, CAM_DEBUG_PROBE, ("Probe completed\n"));
 	while ((done_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs))) {
 		TAILQ_REMOVE(&softc->request_ccbs,
 		    &done_ccb->ccb_h, periph_links.tqe);
 		done_ccb->ccb_h.status = found ? CAM_REQ_CMP : CAM_REQ_CMP_ERR;
 		xpt_done(done_ccb);
 	}
+	cam_periph_invalidate(periph);
 	cam_release_devq(periph->path,
 	    RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_XPT + 1, FALSE);
-	cam_periph_invalidate(periph);
 	cam_periph_release_locked(periph);
 }
 
@@ -1248,8 +1260,10 @@
 
 	quirk = (struct ata_quirk_entry *)match;
 	device->quirk = quirk;
-	if (quirk->quirks & CAM_QUIRK_MAXTAGS)
-		device->mintags = device->maxtags = quirk->maxtags;
+	if (quirk->quirks & CAM_QUIRK_MAXTAGS) {
+		device->mintags = quirk->mintags;
+		device->maxtags = quirk->maxtags;
+	}
 }
 
 typedef struct {
@@ -1473,12 +1487,17 @@
 	}
 
 	if ((old_periph = cam_periph_find(path, "aprobe")) != NULL) {
-		probe_softc *softc;
+		if ((old_periph->flags & CAM_PERIPH_INVALID) == 0) {
+			probe_softc *softc;
 
-		softc = (probe_softc *)old_periph->softc;
-		TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h,
-				  periph_links.tqe);
-		softc->restart = 1;
+			softc = (probe_softc *)old_periph->softc;
+			TAILQ_INSERT_TAIL(&softc->request_ccbs,
+				&request_ccb->ccb_h, periph_links.tqe);
+			softc->restart = 1;
+		} else {
+			request_ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+			xpt_done(request_ccb);
+		}
 	} else {
 		status = cam_periph_alloc(proberegister, NULL, probecleanup,
 					  probestart, "aprobe",
@@ -1624,10 +1643,20 @@
 	device = start_ccb->ccb_h.path->device;
 	cdai = &start_ccb->cdai;
 	switch(cdai->buftype) {
+	case CDAI_TYPE_SCSI_DEVID:
+		if (cdai->flags & CDAI_FLAG_STORE)
+			return;
+		cdai->provsiz = device->device_id_len;
+		if (device->device_id_len == 0)
+			break;
+		amt = device->device_id_len;
+		if (cdai->provsiz > cdai->bufsiz)
+			amt = cdai->bufsiz;
+		memcpy(cdai->buf, device->device_id, amt);
+		break;
 	case CDAI_TYPE_SERIAL_NUM:
 		if (cdai->flags & CDAI_FLAG_STORE)
-			break;
-		start_ccb->ccb_h.status = CAM_REQ_CMP;
+			return;
 		cdai->provsiz = device->serial_num_len;
 		if (device->serial_num_len == 0)
 			break;
@@ -1636,8 +1665,45 @@
 			amt = cdai->bufsiz;
 		memcpy(cdai->buf, device->serial_num, amt);
 		break;
+	case CDAI_TYPE_PHYS_PATH:
+		if (cdai->flags & CDAI_FLAG_STORE) {
+			if (device->physpath != NULL)
+				free(device->physpath, M_CAMXPT);
+			device->physpath_len = cdai->bufsiz;
+			/* Clear existing buffer if zero length */
+			if (cdai->bufsiz == 0)
+				break;
+			device->physpath = malloc(cdai->bufsiz, M_CAMXPT, M_NOWAIT);
+			if (device->physpath == NULL) {
+				start_ccb->ccb_h.status = CAM_REQ_ABORTED;
+				return;
+			}
+			memcpy(device->physpath, cdai->buf, cdai->bufsiz);
+		} else {
+			cdai->provsiz = device->physpath_len;
+			if (device->physpath_len == 0)
+				break;
+			amt = device->physpath_len;
+			if (cdai->provsiz > cdai->bufsiz)
+				amt = cdai->bufsiz;
+			memcpy(cdai->buf, device->physpath, amt);
+		}
+		break;
 	default:
-		break;
+		return;
+	}
+	start_ccb->ccb_h.status = CAM_REQ_CMP;
+
+	if (cdai->flags & CDAI_FLAG_STORE) {
+		int owned;
+
+		owned = mtx_owned(start_ccb->ccb_h.path->bus->sim->mtx);
+		if (owned == 0)
+			mtx_lock(start_ccb->ccb_h.path->bus->sim->mtx);
+		xpt_async(AC_ADVINFO_CHANGED, start_ccb->ccb_h.path,
+			  (void *)(uintptr_t)cdai->buftype);
+		if (owned == 0)
+			mtx_unlock(start_ccb->ccb_h.path->bus->sim->mtx);
 	}
 }
 
@@ -1664,10 +1730,7 @@
 		break;
 	case XPT_GET_TRAN_SETTINGS:
 	{
-		struct cam_sim *sim;
-
-		sim = start_ccb->ccb_h.path->bus->sim;
-		(*(sim->sim_action))(sim, start_ccb);
+		ata_get_transfer_settings(&start_ccb->cts);
 		break;
 	}
 	case XPT_SCSI_IO:
@@ -1706,14 +1769,60 @@
 }
 
 static void
+ata_get_transfer_settings(struct ccb_trans_settings *cts)
+{
+	struct	ccb_trans_settings_ata *ata;
+	struct	ccb_trans_settings_scsi *scsi;
+	struct	cam_ed *device;
+	struct	cam_sim *sim;
+
+	device = cts->ccb_h.path->device;
+	sim = cts->ccb_h.path->bus->sim;
+	(*(sim->sim_action))(sim, (union ccb *)cts);
+
+	if (cts->protocol == PROTO_UNKNOWN ||
+	    cts->protocol == PROTO_UNSPECIFIED) {
+		cts->protocol = device->protocol;
+		cts->protocol_version = device->protocol_version;
+	}
+
+	if (cts->protocol == PROTO_ATA) {
+		ata = &cts->proto_specific.ata;
+		if ((ata->valid & CTS_ATA_VALID_TQ) == 0) {
+			ata->valid |= CTS_ATA_VALID_TQ;
+			if (cts->type == CTS_TYPE_USER_SETTINGS ||
+			    (device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 ||
+			    (device->inq_flags & SID_CmdQue) != 0)
+				ata->flags |= CTS_ATA_FLAGS_TAG_ENB;
+		}
+	}
+	if (cts->protocol == PROTO_SCSI) {
+		scsi = &cts->proto_specific.scsi;
+		if ((scsi->valid & CTS_SCSI_VALID_TQ) == 0) {
+			scsi->valid |= CTS_SCSI_VALID_TQ;
+			if (cts->type == CTS_TYPE_USER_SETTINGS ||
+			    (device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 ||
+			    (device->inq_flags & SID_CmdQue) != 0)
+				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
+		}
+	}
+
+	if (cts->transport == XPORT_UNKNOWN ||
+	    cts->transport == XPORT_UNSPECIFIED) {
+		cts->transport = device->transport;
+		cts->transport_version = device->transport_version;
+	}
+}
+
+static void
 ata_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device,
 			   int async_update)
 {
 	struct	ccb_pathinq cpi;
-	struct	ccb_trans_settings cur_cts;
+	struct	ccb_trans_settings_ata *ata;
 	struct	ccb_trans_settings_scsi *scsi;
-	struct	ccb_trans_settings_scsi *cur_scsi;
 	struct	cam_sim *sim;
+	struct	ata_params *ident_data;
 	struct	scsi_inquiry_data *inq_data;
 
 	if (device == NULL) {
@@ -1773,95 +1882,63 @@
 	}
 
 	sim = cts->ccb_h.path->bus->sim;
-
-	/*
-	 * Nothing more of interest to do unless
-	 * this is a device connected via the
-	 * SCSI protocol.
-	 */
-	if (cts->protocol != PROTO_SCSI) {
-		if (async_update == FALSE)
-			(*(sim->sim_action))(sim, (union ccb *)cts);
-		return;
-	}
-
+	ident_data = &device->ident_data;
 	inq_data = &device->inq_data;
-	scsi = &cts->proto_specific.scsi;
+	if (cts->protocol == PROTO_ATA)
+		ata = &cts->proto_specific.ata;
+	else
+		ata = NULL;
+	if (cts->protocol == PROTO_SCSI)
+		scsi = &cts->proto_specific.scsi;
+	else
+		scsi = NULL;
 	xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, CAM_PRIORITY_NONE);
 	cpi.ccb_h.func_code = XPT_PATH_INQ;
 	xpt_action((union ccb *)&cpi);
 
-	/* SCSI specific sanity checking */
+	/* Sanity checking */
 	if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0
-	 || (INQ_DATA_TQ_ENABLED(inq_data)) == 0
+	 || (ata && (ident_data->satacapabilities & ATA_SUPPORT_NCQ) == 0)
+	 || (scsi && (INQ_DATA_TQ_ENABLED(inq_data)) == 0)
 	 || (device->queue_flags & SCP_QUEUE_DQUE) != 0
 	 || (device->mintags == 0)) {
 		/*
 		 * Can't tag on hardware that doesn't support tags,
 		 * doesn't have it enabled, or has broken tag support.
 		 */
-		scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
-	}
-
-	if (async_update == FALSE) {
-		/*
-		 * Perform sanity checking against what the
-		 * controller and device can do.
-		 */
-		xpt_setup_ccb(&cur_cts.ccb_h, cts->ccb_h.path, CAM_PRIORITY_NONE);
-		cur_cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
-		cur_cts.type = cts->type;
-		xpt_action((union ccb *)&cur_cts);
-		if ((cur_cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
-			return;
-		}
-		cur_scsi = &cur_cts.proto_specific.scsi;
-		if ((scsi->valid & CTS_SCSI_VALID_TQ) == 0) {
-			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
-			scsi->flags |= cur_scsi->flags & CTS_SCSI_FLAGS_TAG_ENB;
-		}
-		if ((cur_scsi->valid & CTS_SCSI_VALID_TQ) == 0)
+		if (ata)
+			ata->flags &= ~CTS_ATA_FLAGS_TAG_ENB;
+		if (scsi)
 			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
 	}
 
-	if (cts->type == CTS_TYPE_CURRENT_SETTINGS
-	 && (scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
-		int device_tagenb;
+	/* Start/stop tags use. */
+	if (cts->type == CTS_TYPE_CURRENT_SETTINGS &&
+	    ((ata && (ata->valid & CTS_ATA_VALID_TQ) != 0) ||
+	     (scsi && (scsi->valid & CTS_SCSI_VALID_TQ) != 0))) {
+		int nowt, newt = 0;
 
-		/*
-		 * If we are transitioning from tags to no-tags or
-		 * vice-versa, we need to carefully freeze and restart
-		 * the queue so that we don't overlap tagged and non-tagged
-		 * commands.  We also temporarily stop tags if there is
-		 * a change in transfer negotiation settings to allow
-		 * "tag-less" negotiation.
-		 */
-		if ((device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0
-		 || (device->inq_flags & SID_CmdQue) != 0)
-			device_tagenb = TRUE;
-		else
-			device_tagenb = FALSE;
+		nowt = ((device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 ||
+			(device->inq_flags & SID_CmdQue) != 0);
+		if (ata)
+			newt = (ata->flags & CTS_ATA_FLAGS_TAG_ENB) != 0;
+		if (scsi)
+			newt = (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0;
 
-		if (((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0
-		  && device_tagenb == FALSE)
-		 || ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) == 0
-		  && device_tagenb == TRUE)) {
+		if (newt && !nowt) {
+			/*
+			 * Delay change to use tags until after a
+			 * few commands have gone to this device so
+			 * the controller has time to perform transfer
+			 * negotiations without tagged messages getting
+			 * in the way.
+			 */
+			device->tag_delay_count = CAM_TAG_DELAY_COUNT;
+			device->flags |= CAM_DEV_TAG_AFTER_COUNT;
+		} else if (nowt && !newt)
+			xpt_stop_tags(cts->ccb_h.path);
+	}
 
-			if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) {
-				/*
-				 * Delay change to use tags until after a
-				 * few commands have gone to this device so
-				 * the controller has time to perform transfer
-				 * negotiations without tagged messages getting
-				 * in the way.
-				 */
-				device->tag_delay_count = CAM_TAG_DELAY_COUNT;
-				device->flags |= CAM_DEV_TAG_AFTER_COUNT;
-			} else {
-				xpt_stop_tags(cts->ccb_h.path);
-			}
-		}
-	}
 	if (async_update == FALSE)
 		(*(sim->sim_action))(sim, (union ccb *)cts);
 }
@@ -1951,11 +2028,11 @@
 	/* Report connection speed */
 	speed = cpi.base_transfer_speed;
 	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_ATA) {
-		struct	ccb_trans_settings_ata *ata =
+		struct	ccb_trans_settings_pata *pata =
 		    &cts.xport_specific.ata;
 
-		if (ata->valid & CTS_ATA_VALID_MODE)
-			speed = ata_mode2speed(ata->mode);
+		if (pata->valid & CTS_ATA_VALID_MODE)
+			speed = ata_mode2speed(pata->mode);
 	}
 	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SATA) {
 		struct	ccb_trans_settings_sata *sata =
@@ -1974,16 +2051,16 @@
 		       periph->unit_number, speed);
 	/* Report additional information about connection */
 	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_ATA) {
-		struct ccb_trans_settings_ata *ata =
+		struct ccb_trans_settings_pata *pata =
 		    &cts.xport_specific.ata;
 
 		printf(" (");
-		if (ata->valid & CTS_ATA_VALID_MODE)
-			printf("%s, ", ata_mode2string(ata->mode));
-		if ((ata->valid & CTS_ATA_VALID_ATAPI) && ata->atapi != 0)
-			printf("ATAPI %dbytes, ", ata->atapi);
-		if (ata->valid & CTS_ATA_VALID_BYTECOUNT)
-			printf("PIO %dbytes", ata->bytecount);
+		if (pata->valid & CTS_ATA_VALID_MODE)
+			printf("%s, ", ata_mode2string(pata->mode));
+		if ((pata->valid & CTS_ATA_VALID_ATAPI) && pata->atapi != 0)
+			printf("ATAPI %dbytes, ", pata->atapi);
+		if (pata->valid & CTS_ATA_VALID_BYTECOUNT)
+			printf("PIO %dbytes", pata->bytecount);
 		printf(")");
 	}
 	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SATA) {
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/cam.h
--- a/head/sys/cam/cam.h	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/cam.h	Wed Jul 25 16:45:04 2012 +0300
@@ -25,7 +25,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/cam/cam.h 236814 2012-06-09 13:07:44Z mav $
  */
 
 #ifndef _CAM_CAM_H
@@ -108,6 +108,15 @@
 	CAM_RETRY_SELTO		= 0x02 /* Retry Selection Timeouts */
 } cam_flags;
 
+enum {
+	SF_RETRY_UA		= 0x01,	/* Retry UNIT ATTENTION conditions. */
+	SF_NO_PRINT		= 0x02,	/* Never print error status. */
+	SF_QUIET_IR		= 0x04,	/* Be quiet about Illegal Request reponses */
+	SF_PRINT_ALWAYS		= 0x08,	/* Always print error status. */
+	SF_NO_RECOVERY		= 0x10,	/* Don't do active error recovery. */
+	SF_NO_RETRY		= 0x20	/* Don't do any retries. */
+};
+
 /* CAM  Status field values */
 typedef enum {
 	CAM_REQ_INPROG,		/* CCB request is in progress */
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/cam_ccb.h
--- a/head/sys/cam/cam_ccb.h	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/cam_ccb.h	Wed Jul 25 16:45:04 2012 +0300
@@ -25,7 +25,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/sys/cam/cam_ccb.h 230590 2012-01-26 18:09:28Z ken $
+ * $FreeBSD: head/sys/cam/cam_ccb.h 236437 2012-06-02 08:29:07Z mav $
  */
 
 #ifndef _CAM_CAM_CCB_H
@@ -242,6 +242,7 @@
 	PROTO_ATA,	/* AT Attachment */
 	PROTO_ATAPI,	/* AT Attachment Packetized Interface */
 	PROTO_SATAPM,	/* SATA Port Multiplier */
+	PROTO_SEMB,	/* SATA Enclosure Management Bridge */
 } cam_proto;
 
 typedef enum {
@@ -843,6 +844,14 @@
 #define	CTS_SCSI_FLAGS_TAG_ENB		0x01
 };
 
+struct ccb_trans_settings_ata
+{
+	u_int	valid;	/* Which fields to honor */
+#define	CTS_ATA_VALID_TQ		0x01
+	u_int	flags;
+#define	CTS_ATA_FLAGS_TAG_ENB		0x01
+};
+
 struct ccb_trans_settings_spi
 {
 	u_int	  valid;	/* Which fields to honor */
@@ -877,7 +886,7 @@
 	u_int32_t 	bitrate;	/* Mbps */
 };
 
-struct ccb_trans_settings_ata {
+struct ccb_trans_settings_pata {
 	u_int     	valid;		/* Which fields to honor */
 #define	CTS_ATA_VALID_MODE		0x01
 #define	CTS_ATA_VALID_BYTECOUNT		0x02
@@ -923,6 +932,7 @@
 	u_int	  transport_version;
 	union {
 		u_int  valid;	/* Which fields to honor */
+		struct ccb_trans_settings_ata ata;
 		struct ccb_trans_settings_scsi scsi;
 	} proto_specific;
 	union {
@@ -930,7 +940,7 @@
 		struct ccb_trans_settings_spi spi;
 		struct ccb_trans_settings_fc fc;
 		struct ccb_trans_settings_sas sas;
-		struct ccb_trans_settings_ata ata;
+		struct ccb_trans_settings_pata ata;
 		struct ccb_trans_settings_sata sata;
 	} xport_specific;
 };
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/cam_debug.h
--- a/head/sys/cam/cam_debug.h	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/cam_debug.h	Wed Jul 25 16:45:04 2012 +0300
@@ -25,7 +25,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/cam/cam_debug.h 236712 2012-06-07 10:05:51Z mav $
  */
 #ifndef	_CAM_CAM_DEBUG_H
 #define _CAM_CAM_DEBUG_H 1
@@ -44,7 +44,35 @@
 	CAM_DEBUG_PROBE		= 0x40  /* print out probe actions */
 } cam_debug_flags;
 
-#if defined(CAMDEBUG) && defined(_KERNEL)
+#if defined(_KERNEL)
+
+#ifndef CAM_DEBUG_FLAGS
+#define CAM_DEBUG_FLAGS		CAM_DEBUG_NONE
+#endif
+
+#ifndef CAM_DEBUG_COMPILE
+#ifdef CAMDEBUG
+#define CAM_DEBUG_COMPILE	(-1)
+#else
+#define CAM_DEBUG_COMPILE	(CAM_DEBUG_INFO | CAM_DEBUG_CDB | \
+				 CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | \
+				 CAM_DEBUG_FLAGS)
+#endif
+#endif
+
+#ifndef CAM_DEBUG_BUS
+#define CAM_DEBUG_BUS		(-1)
+#endif
+#ifndef CAM_DEBUG_TARGET
+#define CAM_DEBUG_TARGET	(-1)
+#endif
+#ifndef CAM_DEBUG_LUN
+#define CAM_DEBUG_LUN		(-1)
+#endif
+
+#ifndef CAM_DEBUG_DELAY
+#define CAM_DEBUG_DELAY		0
+#endif
 
 /* Path we want to debug */
 extern struct cam_path *cam_dpath;
@@ -52,48 +80,48 @@
 extern u_int32_t cam_dflags;
 /* Printf delay value (to prevent scrolling) */
 extern u_int32_t cam_debug_delay;
- 
+
 /* Debugging macros. */
 #define	CAM_DEBUGGED(path, flag)			\
-	((cam_dflags & (flag))				\
+	(((flag) & (CAM_DEBUG_COMPILE) & cam_dflags)	\
 	 && (cam_dpath != NULL)				\
 	 && (xpt_path_comp(cam_dpath, path) >= 0)	\
 	 && (xpt_path_comp(cam_dpath, path) < 2))
 
 #define	CAM_DEBUG(path, flag, printfargs)		\
-	if ((cam_dflags & (flag))			\
+	if (((flag) & (CAM_DEBUG_COMPILE) & cam_dflags)	\
 	 && (cam_dpath != NULL)				\
 	 && (xpt_path_comp(cam_dpath, path) >= 0)	\
 	 && (xpt_path_comp(cam_dpath, path) < 2)) {	\
 		xpt_print_path(path);			\
- 		printf printfargs;			\
+		printf printfargs;			\
 		if (cam_debug_delay != 0)		\
 			DELAY(cam_debug_delay);		\
 	}
 
 #define	CAM_DEBUG_PRINT(flag, printfargs)		\
-	if (cam_dflags & (flag)) {			\
+	if (((flag) & (CAM_DEBUG_COMPILE) & cam_dflags)) {	\
 		printf("cam_debug: ");			\
- 		printf printfargs;			\
+		printf printfargs;			\
 		if (cam_debug_delay != 0)		\
 			DELAY(cam_debug_delay);		\
 	}
 
 #define	CAM_DEBUG_PATH_PRINT(flag, path, printfargs)	\
-	if (cam_dflags & (flag)) {			\
+	if (((flag) & (CAM_DEBUG_COMPILE) & cam_dflags)) {	\
 		xpt_print(path, "cam_debug: ");		\
- 		printf printfargs;			\
+		printf printfargs;			\
 		if (cam_debug_delay != 0)		\
 			DELAY(cam_debug_delay);		\
 	}
 
-#else /* !CAMDEBUG || !_KERNEL */
+#else /* !_KERNEL */
 
 #define	CAM_DEBUGGED(A, B)	0
 #define	CAM_DEBUG(A, B, C)
 #define	CAM_DEBUG_PRINT(A, B)
 #define	CAM_DEBUG_PATH_PRINT(A, B, C)
 
-#endif /* CAMDEBUG && _KERNEL */
+#endif /* _KERNEL */
 
 #endif /* _CAM_CAM_DEBUG_H */
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/cam_periph.c
--- a/head/sys/cam/cam_periph.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/cam_periph.c	Wed Jul 25 16:45:04 2012 +0300
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/cam/cam_periph.c 230544 2012-01-25 17:58:47Z ken $");
+__FBSDID("$FreeBSD: head/sys/cam/cam_periph.c 237682 2012-06-28 03:36:13Z ken $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -69,18 +69,22 @@
 					union ccb *done_ccb);
 static  void		camperiphfree(struct cam_periph *periph);
 static int		camperiphscsistatuserror(union ccb *ccb,
+					        union ccb **orig_ccb,
 						 cam_flags camflags,
 						 u_int32_t sense_flags,
 						 int *openings,
 						 u_int32_t *relsim_flags,
 						 u_int32_t *timeout,
+						 int *print,
 						 const char **action_string);
 static	int		camperiphscsisenseerror(union ccb *ccb,
+					        union ccb **orig_ccb,
 					        cam_flags camflags,
 					        u_int32_t sense_flags,
 					        int *openings,
 					        u_int32_t *relsim_flags,
 					        u_int32_t *timeout,
+					        int *print,
 					        const char **action_string);
 
 static int nperiph_drivers;
@@ -240,6 +244,7 @@
 		goto failure;
 
 	init_level++;
+	CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("Periph created\n"));
 
 	status = periph_ctor(periph, arg);
 
@@ -252,7 +257,8 @@
 		/* Initialized successfully */
 		break;
 	case 3:
-		xpt_remove_periph(periph);
+		CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("Periph destroyed\n"));
+		xpt_remove_periph(periph, /*topology_lock_held*/ 0);
 		/* FALLTHROUGH */
 	case 2:
 		xpt_lock_buses();
@@ -267,7 +273,7 @@
 		/* No cleanup to perform. */
 		break;
 	default:
-		panic("cam_periph_alloc: Unkown init level");
+		panic("%s: Unknown init level", __func__);
 	}
 	return(status);
 }
@@ -434,6 +440,10 @@
 			cam_periph_release_locked(periph);
 			return (error);
 		}
+		if (periph->flags & CAM_PERIPH_INVALID) {
+			cam_periph_release_locked(periph);
+			return (ENXIO);
+		}
 	}
 
 	periph->flags |= CAM_PERIPH_LOCKED;
@@ -572,6 +582,7 @@
 cam_periph_invalidate(struct cam_periph *periph)
 {
 
+	CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("Periph invalidated\n"));
 	/*
 	 * We only call this routine the first time a peripheral is
 	 * invalidated.
@@ -603,13 +614,39 @@
 		return;
 	}
 
+	/*
+	 * The peripheral destructor semantics dictate calling with only the
+	 * SIM mutex held.  Since it might sleep, it should not be called
+	 * with the topology lock held.
+	 */
+	xpt_unlock_buses();
+
+	/*
+	 * We need to call the peripheral destructor prior to removing the
+	 * peripheral from the list.  Otherwise, we risk running into a
+	 * scenario where the peripheral unit number may get reused
+	 * (because it has been removed from the list), but some resources
+	 * used by the peripheral are still hanging around.  In particular,
+	 * the devfs nodes used by some peripherals like the pass(4) driver
+	 * aren't fully cleaned up until the destructor is run.  If the
+	 * unit number is reused before the devfs instance is fully gone,
+	 * devfs will panic.
+	 */
+	if (periph->periph_dtor != NULL)
+		periph->periph_dtor(periph);
+
+	/*
+	 * The peripheral list is protected by the topology lock.
+	 */
+	xpt_lock_buses();
+
 	TAILQ_REMOVE(&(*p_drv)->units, periph, unit_links);
 	(*p_drv)->generation++;
+
+	xpt_remove_periph(periph, /*topology_lock_held*/ 1);
+
 	xpt_unlock_buses();
-
-	if (periph->periph_dtor != NULL)
-		periph->periph_dtor(periph);
-	xpt_remove_periph(periph);
+	CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("Periph destroyed\n"));
 
 	if (periph->flags & CAM_PERIPH_NEW_DEV_FOUND) {
 		union ccb ccb;
@@ -1104,107 +1141,52 @@
 }
 
 #define saved_ccb_ptr ppriv_ptr0
-#define recovery_depth ppriv_field1
-static void
-camperiphsensedone(struct cam_periph *periph, union ccb *done_ccb)
-{
-	union ccb      *saved_ccb = (union ccb *)done_ccb->ccb_h.saved_ccb_ptr;
-	cam_status	status;
-	int		frozen = 0;
-	int		depth = done_ccb->ccb_h.recovery_depth;
-
-	status = done_ccb->ccb_h.status;
-	if (status & CAM_DEV_QFRZN) {
-		frozen = 1;
-		/*
-		 * Clear freeze flag now for case of retry,
-		 * freeze will be dropped later.
-		 */
-		done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
-	}
-	status &= CAM_STATUS_MASK;
-	switch (status) {
-	case CAM_REQ_CMP:
-	{
-		int error_code, sense_key, asc, ascq;
-
-		scsi_extract_sense_len(&saved_ccb->csio.sense_data,
-				       saved_ccb->csio.sense_len -
-				       saved_ccb->csio.sense_resid,
-				       &error_code, &sense_key, &asc, &ascq,
-				       /*show_errors*/ 1);
-		/*
-		 * If we manually retrieved sense into a CCB and got
-		 * something other than "NO SENSE" send the updated CCB
-		 * back to the client via xpt_done() to be processed via
-		 * the error recovery code again.
-		 */
-		if ((sense_key != -1)
-		 && (sense_key != SSD_KEY_NO_SENSE)) {
-			saved_ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
-		} else {
-			saved_ccb->ccb_h.status &= ~CAM_STATUS_MASK;
-			saved_ccb->ccb_h.status |= CAM_AUTOSENSE_FAIL;
-		}
-		saved_ccb->csio.sense_resid = done_ccb->csio.resid;
-		bcopy(saved_ccb, done_ccb, sizeof(union ccb));
-		xpt_free_ccb(saved_ccb);
-		break;
-	}
-	default:
-		bcopy(saved_ccb, done_ccb, sizeof(union ccb));
-		xpt_free_ccb(saved_ccb);
-		done_ccb->ccb_h.status &= ~CAM_STATUS_MASK;
-		done_ccb->ccb_h.status |= CAM_AUTOSENSE_FAIL;
-		break;
-	}
-	periph->flags &= ~CAM_PERIPH_SENSE_INPROG;
-	/*
-	 * If it is the end of recovery, drop freeze, taken due to
-	 * CAM_DEV_QFREEZE flag, set on recovery request.
-	 */
-	if (depth == 0) {
-		cam_release_devq(done_ccb->ccb_h.path,
-			 /*relsim_flags*/0,
-			 /*openings*/0,
-			 /*timeout*/0,
-			 /*getcount_only*/0);
-	}
-	/*
-	 * Copy frozen flag from recovery request if it is set there
-	 * for some reason.
-	 */
-	if (frozen != 0)
-		done_ccb->ccb_h.status |= CAM_DEV_QFRZN;
-	(*done_ccb->ccb_h.cbfcnp)(periph, done_ccb);
-}
-
 static void
 camperiphdone(struct cam_periph *periph, union ccb *done_ccb)
 {
-	union ccb      *saved_ccb, *save_ccb;
+	union ccb      *saved_ccb;
 	cam_status	status;
-	int		frozen = 0;
 	struct scsi_start_stop_unit *scsi_cmd;
-	u_int32_t	relsim_flags, timeout;
+	int    error_code, sense_key, asc, ascq;
 
+	scsi_cmd = (struct scsi_start_stop_unit *)
+	    &done_ccb->csio.cdb_io.cdb_bytes;
 	status = done_ccb->ccb_h.status;
-	if (status & CAM_DEV_QFRZN) {
-		frozen = 1;
-		/*
-		 * Clear freeze flag now for case of retry,
-		 * freeze will be dropped later.
-		 */
-		done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
-	}
 
-	timeout = 0;
-	relsim_flags = 0;
-	saved_ccb = (union ccb *)done_ccb->ccb_h.saved_ccb_ptr;
-
-	switch (status & CAM_STATUS_MASK) {
-	case CAM_REQ_CMP:
-	{
+	if ((status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+		if (scsi_extract_sense_ccb(done_ccb,
+		    &error_code, &sense_key, &asc, &ascq)) {
+			/*
+			 * If the error is "invalid field in CDB",
+			 * and the load/eject flag is set, turn the
+			 * flag off and try again.  This is just in
+			 * case the drive in question barfs on the
+			 * load eject flag.  The CAM code should set
+			 * the load/eject flag by default for
+			 * removable media.
+			 */
+			if ((scsi_cmd->opcode == START_STOP_UNIT) &&
+			    ((scsi_cmd->how & SSS_LOEJ) != 0) &&
+			     (asc == 0x24) && (ascq == 0x00)) {
+				scsi_cmd->how &= ~SSS_LOEJ;
+				if (status & CAM_DEV_QFRZN) {
+					cam_release_devq(done_ccb->ccb_h.path,
+					    0, 0, 0, 0);
+					done_ccb->ccb_h.status &=
+					    ~CAM_DEV_QFRZN;
+				}
+				xpt_action(done_ccb);
+				goto out;
+			}
+		}
+		if (cam_periph_error(done_ccb,
+		    0, SF_RETRY_UA | SF_NO_PRINT, NULL) == ERESTART)
+			goto out;
+		if (done_ccb->ccb_h.status & CAM_DEV_QFRZN) {
+			cam_release_devq(done_ccb->ccb_h.path, 0, 0, 0, 0);
+			done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
+		}
+	} else {
 		/*
 		 * If we have successfully taken a device from the not
 		 * ready to ready state, re-scan the device and re-get
@@ -1212,147 +1194,24 @@
 		 * don't properly report their inquiry information unless
 		 * they are spun up.
 		 */
-		scsi_cmd = (struct scsi_start_stop_unit *)
-				&done_ccb->csio.cdb_io.cdb_bytes;
-
-	 	if (scsi_cmd->opcode == START_STOP_UNIT)
-			xpt_async(AC_INQ_CHANGED,
-				  done_ccb->ccb_h.path, NULL);
-		goto final;
-	}
-	case CAM_SCSI_STATUS_ERROR:
-		scsi_cmd = (struct scsi_start_stop_unit *)
-				&done_ccb->csio.cdb_io.cdb_bytes;
-		if (status & CAM_AUTOSNS_VALID) {
-			struct ccb_getdev cgd;
-			struct scsi_sense_data *sense;
-			int    error_code, sense_key, asc, ascq, sense_len;
-			scsi_sense_action err_action;
-
-			sense = &done_ccb->csio.sense_data;
-			sense_len = done_ccb->csio.sense_len -
-				    done_ccb->csio.sense_resid;
-			scsi_extract_sense_len(sense, sense_len, &error_code, 
-					       &sense_key, &asc, &ascq,
-					       /*show_errors*/ 1);
-			/*
-			 * Grab the inquiry data for this device.
-			 */
-			xpt_setup_ccb(&cgd.ccb_h, done_ccb->ccb_h.path,
-			    CAM_PRIORITY_NORMAL);
-			cgd.ccb_h.func_code = XPT_GDEV_TYPE;
-			xpt_action((union ccb *)&cgd);
-			err_action = scsi_error_action(&done_ccb->csio,
-						       &cgd.inq_data, 0);
-			/*
-	 		 * If the error is "invalid field in CDB", 
-			 * and the load/eject flag is set, turn the 
-			 * flag off and try again.  This is just in 
-			 * case the drive in question barfs on the 
-			 * load eject flag.  The CAM code should set 
-			 * the load/eject flag by default for 
-			 * removable media.
-			 */
-			/* XXX KDM 
-			 * Should we check to see what the specific
-			 * scsi status is??  Or does it not matter
-			 * since we already know that there was an
-			 * error, and we know what the specific
-			 * error code was, and we know what the
-			 * opcode is..
-			 */
-			if ((scsi_cmd->opcode == START_STOP_UNIT) &&
-			    ((scsi_cmd->how & SSS_LOEJ) != 0) &&
-			     (asc == 0x24) && (ascq == 0x00) &&
-			     (done_ccb->ccb_h.retry_count > 0)) {
-
-				scsi_cmd->how &= ~SSS_LOEJ;
-				xpt_action(done_ccb);
-			} else if ((done_ccb->ccb_h.retry_count > 1)
-				&& ((err_action & SS_MASK) != SS_FAIL)) {
-
-				/*
-				 * In this case, the error recovery
-				 * command failed, but we've got 
-				 * some retries left on it.  Give
-				 * it another try unless this is an
-				 * unretryable error.
-				 */
-				/* set the timeout to .5 sec */
-				relsim_flags =
-					RELSIM_RELEASE_AFTER_TIMEOUT;
-				timeout = 500;
-				xpt_action(done_ccb);
-				break;
-			} else {
-				/* 
-				 * Perform the final retry with the original
-				 * CCB so that final error processing is
-				 * performed by the owner of the CCB.
-				 */
-				goto final;
-			}
-		} else {
-			save_ccb = xpt_alloc_ccb_nowait();
-			if (save_ccb == NULL)
-				goto final;
-			bcopy(done_ccb, save_ccb, sizeof(*save_ccb));
-			periph->flags |= CAM_PERIPH_SENSE_INPROG;
-			/*
-			 * Send a Request Sense to the device.  We
-			 * assume that we are in a contingent allegiance
-			 * condition so we do not tag this request.
-			 */
-			scsi_request_sense(&done_ccb->csio, /*retries*/1,
-					   camperiphsensedone,
-					   &save_ccb->csio.sense_data,
-					   save_ccb->csio.sense_len,
-					   CAM_TAG_ACTION_NONE,
-					   /*sense_len*/SSD_FULL_SIZE,
-					   /*timeout*/5000);
-			done_ccb->ccb_h.pinfo.priority--;
-			done_ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
-			done_ccb->ccb_h.saved_ccb_ptr = save_ccb;
-			done_ccb->ccb_h.recovery_depth++;
-			xpt_action(done_ccb);
-		}
-		break;
-	default:
-final:
-		bcopy(saved_ccb, done_ccb, sizeof(*done_ccb));
-		xpt_free_ccb(saved_ccb);
-		periph->flags &= ~CAM_PERIPH_RECOVERY_INPROG;
-		xpt_action(done_ccb);
-		break;
+		if (scsi_cmd->opcode == START_STOP_UNIT)
+			xpt_async(AC_INQ_CHANGED, done_ccb->ccb_h.path, NULL);
 	}
 
-	/* decrement the retry count */
 	/*
-	 * XXX This isn't appropriate in all cases.  Restructure,
-	 *     so that the retry count is only decremented on an
-	 *     actual retry.  Remeber that the orignal ccb had its
-	 *     retry count dropped before entering recovery, so
-	 *     doing it again is a bug.
+	 * Perform the final retry with the original CCB so that final
+	 * error processing is performed by the owner of the CCB.
 	 */
-	if (done_ccb->ccb_h.retry_count > 0)
-		done_ccb->ccb_h.retry_count--;
-	/*
-	 * Drop freeze taken due to CAM_DEV_QFREEZE flag set on recovery
-	 * request.
-	 */
-	cam_release_devq(done_ccb->ccb_h.path,
-			 /*relsim_flags*/relsim_flags,
-			 /*openings*/0,
-			 /*timeout*/timeout,
-			 /*getcount_only*/0);
-	/* Drop freeze taken, if this recovery request got error. */
-	if (frozen != 0) {
-		cam_release_devq(done_ccb->ccb_h.path,
-			 /*relsim_flags*/0,
-			 /*openings*/0,
-			 /*timeout*/0,
-			 /*getcount_only*/0);
-	}
+	saved_ccb = (union ccb *)done_ccb->ccb_h.saved_ccb_ptr;
+	bcopy(saved_ccb, done_ccb, sizeof(*done_ccb));
+	xpt_free_ccb(saved_ccb);
+	if (done_ccb->ccb_h.cbfcnp != camperiphdone)
+		periph->flags &= ~CAM_PERIPH_RECOVERY_INPROG;
+	xpt_action(done_ccb);
+
+out:
+	/* Drop freeze taken due to CAM_DEV_QFREEZE flag set. */
+	cam_release_devq(done_ccb->ccb_h.path, 0, 0, 0, 0);
 }
 
 /*
@@ -1411,10 +1270,10 @@
 }
 
 static int
-camperiphscsistatuserror(union ccb *ccb, cam_flags camflags,
-			 u_int32_t sense_flags,
-			 int *openings, u_int32_t *relsim_flags,
-			 u_int32_t *timeout, const char **action_string)
+camperiphscsistatuserror(union ccb *ccb, union ccb **orig_ccb,
+    cam_flags camflags, u_int32_t sense_flags,
+    int *openings, u_int32_t *relsim_flags,
+    u_int32_t *timeout, int *print, const char **action_string)
 {
 	int error;
 
@@ -1427,14 +1286,13 @@
 		break;
 	case SCSI_STATUS_CMD_TERMINATED:
 	case SCSI_STATUS_CHECK_COND:
-		if (bootverbose)
-			xpt_print(ccb->ccb_h.path, "SCSI status error\n");
-		error = camperiphscsisenseerror(ccb,
+		error = camperiphscsisenseerror(ccb, orig_ccb,
 					        camflags,
 					        sense_flags,
 					        openings,
 					        relsim_flags,
 					        timeout,
+					        print,
 					        action_string);
 		break;
 	case SCSI_STATUS_QUEUE_FULL:
@@ -1489,9 +1347,7 @@
 			}
 			*timeout = 0;
 			error = ERESTART;
-			if (bootverbose) {
-				xpt_print(ccb->ccb_h.path, "Queue full\n");
-			}
+			*print = 0;
 			break;
 		}
 		/* FALLTHROUGH */
@@ -1501,9 +1357,6 @@
 		 * Restart the queue after either another
 		 * command completes or a 1 second timeout.
 		 */
-		if (bootverbose) {
-			xpt_print(ccb->ccb_h.path, "Device busy\n");
-		}
 	 	if (ccb->ccb_h.retry_count > 0) {
 	 		ccb->ccb_h.retry_count--;
 			error = ERESTART;
@@ -1515,12 +1368,7 @@
 		}
 		break;
 	case SCSI_STATUS_RESERV_CONFLICT:
-		xpt_print(ccb->ccb_h.path, "Reservation conflict\n");
-		error = EIO;
-		break;
 	default:
-		xpt_print(ccb->ccb_h.path, "SCSI status 0x%x\n",
-		    ccb->csio.scsi_status);
 		error = EIO;
 		break;
 	}
@@ -1528,18 +1376,18 @@
 }
 
 static int
-camperiphscsisenseerror(union ccb *ccb, cam_flags camflags,
-			u_int32_t sense_flags,
-		       int *openings, u_int32_t *relsim_flags,
-		       u_int32_t *timeout, const char **action_string)
+camperiphscsisenseerror(union ccb *ccb, union ccb **orig,
+    cam_flags camflags, u_int32_t sense_flags,
+    int *openings, u_int32_t *relsim_flags,
+    u_int32_t *timeout, int *print, const char **action_string)
 {
 	struct cam_periph *periph;
 	union ccb *orig_ccb = ccb;
-	int error;
+	int error, recoveryccb;
 
 	periph = xpt_path_periph(ccb->ccb_h.path);
-	if (periph->flags &
-	    (CAM_PERIPH_RECOVERY_INPROG | CAM_PERIPH_SENSE_INPROG)) {
+	recoveryccb = (ccb->ccb_h.cbfcnp == camperiphdone);
+	if ((periph->flags & CAM_PERIPH_RECOVERY_INPROG) && !recoveryccb) {
 		/*
 		 * If error recovery is already in progress, don't attempt
 		 * to process this error, but requeue it unconditionally
@@ -1554,6 +1402,7 @@
 		 * imperitive that we don't violate this assumption.
 		 */
 		error = ERESTART;
+		*print = 0;
 	} else {
 		scsi_sense_action err_action;
 		struct ccb_getdev cgd;
@@ -1565,16 +1414,34 @@
 		cgd.ccb_h.func_code = XPT_GDEV_TYPE;
 		xpt_action((union ccb *)&cgd);
 
-		if ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0)
-			err_action = scsi_error_action(&ccb->csio,
-						       &cgd.inq_data,
-						       sense_flags);
-		else if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0)
-			err_action = SS_REQSENSE;
-		else
-			err_action = SS_RETRY|SSQ_DECREMENT_COUNT|EIO;
+		err_action = scsi_error_action(&ccb->csio, &cgd.inq_data,
+		    sense_flags);
+		error = err_action & SS_ERRMASK;
 
-		error = err_action & SS_ERRMASK;
+		/*
+		 * Do not autostart sequential access devices
+		 * to avoid unexpected tape loading.
+		 */
+		if ((err_action & SS_MASK) == SS_START &&
+		    SID_TYPE(&cgd.inq_data) == T_SEQUENTIAL) {
+			*action_string = "Will not autostart a "
+			    "sequential access device";
+			goto sense_error_done;
+		}
+
+		/*
+		 * Avoid recovery recursion if recovery action is the same.
+		 */
+		if ((err_action & SS_MASK) >= SS_START && recoveryccb) {
+			if (((err_action & SS_MASK) == SS_START &&
+			     ccb->csio.cdb_io.cdb_bytes[0] == START_STOP_UNIT) ||
+			    ((err_action & SS_MASK) == SS_TUR &&
+			     (ccb->csio.cdb_io.cdb_bytes[0] == TEST_UNIT_READY))) {
+				err_action = SS_RETRY|SSQ_DECREMENT_COUNT|EIO;
+				*relsim_flags = RELSIM_RELEASE_AFTER_TIMEOUT;
+				*timeout = 500;
+			}
+		}
 
 		/*
 		 * If the recovery action will consume a retry,
@@ -1623,15 +1490,6 @@
 		case SS_START:
 		{
 			int le;
-			if (SID_TYPE(&cgd.inq_data) == T_SEQUENTIAL) {
-				xpt_free_ccb(orig_ccb);
-				ccb->ccb_h.status |= CAM_DEV_QFRZN;
-				*action_string = "Will not autostart a "
-				    "sequential access device";
-				err_action = SS_FAIL;
-				error = EIO;
-				break;
-			}
 
 			/*
 			 * Send a start unit command to the device, and
@@ -1695,24 +1553,6 @@
 			*timeout = 500;
 			break;
 		}
-		case SS_REQSENSE:
-		{
-			*action_string = "Requesting SCSI sense data";
-			periph->flags |= CAM_PERIPH_SENSE_INPROG;
-			/*
-			 * Send a Request Sense to the device.  We
-			 * assume that we are in a contingent allegiance
-			 * condition so we do not tag this request.
-			 */
-			scsi_request_sense(&ccb->csio, /*retries*/1,
-					   camperiphsensedone,
-					   &orig_ccb->csio.sense_data,
-					   orig_ccb->csio.sense_len,
-					   CAM_TAG_ACTION_NONE,
-					   /*sense_len*/SSD_FULL_SIZE,
-					   /*timeout*/5000);
-			break;
-		}
 		default:
 			panic("Unhandled error action %x", err_action);
 		}
@@ -1729,14 +1569,12 @@
 			ccb->ccb_h.pinfo.priority--;
 			ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
 			ccb->ccb_h.saved_ccb_ptr = orig_ccb;
-			ccb->ccb_h.recovery_depth = 0;
 			error = ERESTART;
+			*orig = orig_ccb;
 		}
 
 sense_error_done:
-		if ((err_action & SSQ_PRINT_SENSE) != 0
-		 && (ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0)
-			cam_error_print(orig_ccb, CAM_ESF_ALL, CAM_EPF_ALL);
+		*print = ((err_action & SSQ_PRINT_SENSE) != 0);
 	}
 	return (error);
 }
@@ -1750,87 +1588,35 @@
 cam_periph_error(union ccb *ccb, cam_flags camflags,
 		 u_int32_t sense_flags, union ccb *save_ccb)
 {
+	union ccb  *orig_ccb;
 	struct cam_periph *periph;
 	const char *action_string;
 	cam_status  status;
-	int	    frozen;
-	int	    error, printed = 0;
-	int         openings;
-	u_int32_t   relsim_flags;
-	u_int32_t   timeout = 0;
+	int	    frozen, error, openings, print, lost_device;
+	u_int32_t   relsim_flags, timeout;
 
+	print = 1;
 	periph = xpt_path_periph(ccb->ccb_h.path);
 	action_string = NULL;
 	status = ccb->ccb_h.status;
 	frozen = (status & CAM_DEV_QFRZN) != 0;
 	status &= CAM_STATUS_MASK;
-	openings = relsim_flags = 0;
+	openings = relsim_flags = timeout = lost_device = 0;
+	orig_ccb = ccb;
 
 	switch (status) {
 	case CAM_REQ_CMP:
 		error = 0;
+		print = 0;
 		break;
 	case CAM_SCSI_STATUS_ERROR:
-		error = camperiphscsistatuserror(ccb,
-						 camflags,
-						 sense_flags,
-						 &openings,
-						 &relsim_flags,
-						 &timeout,
-						 &action_string);
+		error = camperiphscsistatuserror(ccb, &orig_ccb,
+		    camflags, sense_flags, &openings, &relsim_flags,
+		    &timeout, &print, &action_string);
 		break;
 	case CAM_AUTOSENSE_FAIL:
-		xpt_print(ccb->ccb_h.path, "AutoSense failed\n");
 		error = EIO;	/* we have to kill the command */
 		break;
-	case CAM_ATA_STATUS_ERROR:
-		if (bootverbose && printed == 0) {
-			xpt_print(ccb->ccb_h.path, "ATA status error\n");
-			cam_error_print(ccb, CAM_ESF_ALL, CAM_EPF_ALL);
-			printed++;
-		}
-		/* FALLTHROUGH */
-	case CAM_REQ_CMP_ERR:
-		if (bootverbose && printed == 0) {
-			xpt_print(ccb->ccb_h.path,
-			    "Request completed with CAM_REQ_CMP_ERR\n");
-			printed++;
-		}
-		/* FALLTHROUGH */
-	case CAM_CMD_TIMEOUT:
-		if (bootverbose && printed == 0) {
-			xpt_print(ccb->ccb_h.path, "Command timed out\n");
-			printed++;
-		}
-		/* FALLTHROUGH */
-	case CAM_UNEXP_BUSFREE:
-		if (bootverbose && printed == 0) {
-			xpt_print(ccb->ccb_h.path, "Unexpected Bus Free\n");
-			printed++;
-		}
-		/* FALLTHROUGH */
-	case CAM_UNCOR_PARITY:
-		if (bootverbose && printed == 0) {
-			xpt_print(ccb->ccb_h.path,
-			    "Uncorrected parity error\n");
-			printed++;
-		}
-		/* FALLTHROUGH */
-	case CAM_DATA_RUN_ERR:
-		if (bootverbose && printed == 0) {
-			xpt_print(ccb->ccb_h.path, "Data overrun\n");
-			printed++;
-		}
-		/* decrement the number of retries */
-		if (ccb->ccb_h.retry_count > 0 &&
-		    (periph->flags & CAM_PERIPH_INVALID) == 0) {
-			ccb->ccb_h.retry_count--;
-			error = ERESTART;
-		} else {
-			action_string = "Retries exhausted";
-			error = EIO;
-		}
-		break;
 	case CAM_UA_ABORT:
 	case CAM_UA_TERMIO:
 	case CAM_MSG_REJECT_REC:
@@ -1841,14 +1627,8 @@
 		if ((camflags & CAM_RETRY_SELTO) != 0) {
 			if (ccb->ccb_h.retry_count > 0 &&
 			    (periph->flags & CAM_PERIPH_INVALID) == 0) {
-
 				ccb->ccb_h.retry_count--;
 				error = ERESTART;
-				if (bootverbose && printed == 0) {
-					xpt_print(ccb->ccb_h.path,
-					    "Selection timeout\n");
-					printed++;
-				}
 
 				/*
 				 * Wait a bit to give the device
@@ -1862,38 +1642,10 @@
 		}
 		/* FALLTHROUGH */
 	case CAM_DEV_NOT_THERE:
-	{
-		struct cam_path *newpath;
-		lun_id_t lun_id;
-
 		error = ENXIO;
-
-		/*
-		 * For a selection timeout, we consider all of the LUNs on
-		 * the target to be gone.  If the status is CAM_DEV_NOT_THERE,
-		 * then we only get rid of the device(s) specified by the
-		 * path in the original CCB.
-		 */
-		if (status == CAM_DEV_NOT_THERE)
-			lun_id = xpt_path_lun_id(ccb->ccb_h.path);
-		else
-			lun_id = CAM_LUN_WILDCARD;
-
-		/* Should we do more if we can't create the path?? */
-		if (xpt_create_path(&newpath, periph,
-				    xpt_path_path_id(ccb->ccb_h.path),
-				    xpt_path_target_id(ccb->ccb_h.path),
-				    lun_id) != CAM_REQ_CMP) 
-			break;
-
-		/*
-		 * Let peripheral drivers know that this device has gone
-		 * away.
-		 */
-		xpt_async(AC_LOST_DEVICE, newpath, NULL);
-		xpt_free_path(newpath);
+		print = 0;
+		lost_device = 1;
 		break;
-	}
 	case CAM_REQ_INVALID:
 	case CAM_PATH_INVALID:
 	case CAM_NO_HBA:
@@ -1913,26 +1665,17 @@
 		 * these events and should be unconditionally
 		 * retried.
 		 */
-		if (bootverbose && printed == 0) {
-			xpt_print_path(ccb->ccb_h.path);
-			if (status == CAM_BDR_SENT)
-				printf("Bus Device Reset sent\n");
-			else
-				printf("Bus Reset issued\n");
-			printed++;
-		}
-		/* FALLTHROUGH */
 	case CAM_REQUEUE_REQ:
-		/* Unconditional requeue */
-		if (bootverbose && printed == 0) {
-			xpt_print(ccb->ccb_h.path, "Request requeued\n");
-			printed++;
-		}
-		if ((periph->flags & CAM_PERIPH_INVALID) == 0)
+		/* Unconditional requeue if device is still there */
+		if (periph->flags & CAM_PERIPH_INVALID) {
+			action_string = "Periph was invalidated";
+			error = EIO;
+		} else if (sense_flags & SF_NO_RETRY) {
+			error = EIO;
+			action_string = "Retry was blocked";
+		} else {
 			error = ERESTART;
-		else {
-			action_string = "Retries exhausted";
-			error = EIO;
+			print = 0;
 		}
 		break;
 	case CAM_RESRC_UNAVAIL:
@@ -1946,30 +1689,37 @@
 		}
 		relsim_flags = RELSIM_RELEASE_AFTER_TIMEOUT;
 		/* FALLTHROUGH */
+	case CAM_ATA_STATUS_ERROR:
+	case CAM_REQ_CMP_ERR:
+	case CAM_CMD_TIMEOUT:
+	case CAM_UNEXP_BUSFREE:
+	case CAM_UNCOR_PARITY:
+	case CAM_DATA_RUN_ERR:
 	default:
-		/* decrement the number of retries */
-		if (ccb->ccb_h.retry_count > 0 &&
-		    (periph->flags & CAM_PERIPH_INVALID) == 0) {
+		if (periph->flags & CAM_PERIPH_INVALID) {
+			error = EIO;
+			action_string = "Periph was invalidated";
+		} else if (ccb->ccb_h.retry_count == 0) {
+			error = EIO;
+			action_string = "Retries exhausted";
+		} else if (sense_flags & SF_NO_RETRY) {
+			error = EIO;
+			action_string = "Retry was blocked";
+		} else {
 			ccb->ccb_h.retry_count--;
 			error = ERESTART;
-			if (bootverbose && printed == 0) {
-				xpt_print(ccb->ccb_h.path, "CAM status 0x%x\n",
-				    status);
-				printed++;
-			}
-		} else {
-			error = EIO;
-			action_string = "Retries exhausted";
 		}
 		break;
 	}
 
-	/*
-	 * If we have and error and are booting verbosely, whine
-	 * *unless* this was a non-retryable selection timeout.
-	 */
-	if (error != 0 && bootverbose &&
-	    !(status == CAM_SEL_TIMEOUT && (camflags & CAM_RETRY_SELTO) == 0)) {
+	if ((sense_flags & SF_PRINT_ALWAYS) ||
+	    CAM_DEBUGGED(ccb->ccb_h.path, CAM_DEBUG_INFO))
+		print = 1;
+	else if (sense_flags & SF_NO_PRINT)
+		print = 0;
+	if (print)
+		cam_error_print(orig_ccb, CAM_ESF_ALL, CAM_EPF_ALL);
+	if (error != 0 && print) {
 		if (error != ERESTART) {
 			if (action_string == NULL)
 				action_string = "Unretryable error";
@@ -1981,6 +1731,36 @@
 			xpt_print(ccb->ccb_h.path, "Retrying command\n");
 	}
 
+	if (lost_device) {
+		struct cam_path *newpath;
+		lun_id_t lun_id;
+
+		/*
+		 * For a selection timeout, we consider all of the LUNs on
+		 * the target to be gone.  If the status is CAM_DEV_NOT_THERE,
+		 * then we only get rid of the device(s) specified by the
+		 * path in the original CCB.
+		 */
+		if (status == CAM_DEV_NOT_THERE)
+			lun_id = xpt_path_lun_id(ccb->ccb_h.path);
+		else
+			lun_id = CAM_LUN_WILDCARD;
+
+		/* Should we do more if we can't create the path?? */
+		if (xpt_create_path(&newpath, periph,
+				    xpt_path_path_id(ccb->ccb_h.path),
+				    xpt_path_target_id(ccb->ccb_h.path),
+				    lun_id) == CAM_REQ_CMP) {
+
+			/*
+			 * Let peripheral drivers know that this
+			 * device has gone away.
+			 */
+			xpt_async(AC_LOST_DEVICE, newpath, NULL);
+			xpt_free_path(newpath);
+		}
+	}
+
 	/* Attempt a retry */
 	if (error == ERESTART || error == 0) {
 		if (frozen != 0)
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/cam_periph.h
--- a/head/sys/cam/cam_periph.h	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/cam_periph.h	Wed Jul 25 16:45:04 2012 +0300
@@ -25,7 +25,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/sys/cam/cam_periph.h 230000 2012-01-12 00:41:48Z ken $
+ * $FreeBSD: head/sys/cam/cam_periph.h 236814 2012-06-09 13:07:44Z mav $
  */
 
 #ifndef _CAM_CAM_PERIPH_H
@@ -118,7 +118,6 @@
 #define CAM_PERIPH_INVALID		0x08
 #define CAM_PERIPH_NEW_DEV_FOUND	0x10
 #define CAM_PERIPH_RECOVERY_INPROG	0x20
-#define CAM_PERIPH_SENSE_INPROG		0x40
 #define CAM_PERIPH_FREE			0x80
 	u_int32_t		 immediate_priority;
 	u_int32_t		 refcount;
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/cam_sim.h
--- a/head/sys/cam/cam_sim.h	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/cam_sim.h	Wed Jul 25 16:45:04 2012 +0300
@@ -25,7 +25,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/sys/cam/cam_sim.h 227637 2011-11-17 21:07:56Z mav $
+ * $FreeBSD: head/sys/cam/cam_sim.h 235333 2012-05-12 13:55:36Z mav $
  */
 
 #ifndef _CAM_CAM_SIM_H
@@ -106,6 +106,7 @@
 #define	CAM_SIM_MPSAFE			0x02
 #define	CAM_SIM_ON_DONEQ		0x04
 #define	CAM_SIM_POLLED			0x08
+#define	CAM_SIM_BATCH			0x10
 	struct callout		callout;
 	struct cam_devq 	*devq;	/* Device Queue to use for this SIM */
 	int			refcount; /* References to the SIM. */
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/cam_xpt.c
--- a/head/sys/cam/cam_xpt.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/cam_xpt.c	Wed Jul 25 16:45:04 2012 +0300
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/cam/cam_xpt.c 230590 2012-01-26 18:09:28Z ken $");
+__FBSDID("$FreeBSD: head/sys/cam/cam_xpt.c 237398 2012-06-21 14:35:46Z mav $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -188,21 +188,15 @@
 };
 
 /* Storage for debugging datastructures */
-#ifdef	CAMDEBUG
 struct cam_path *cam_dpath;
-#ifdef	CAM_DEBUG_FLAGS
 u_int32_t cam_dflags = CAM_DEBUG_FLAGS;
-#else
-u_int32_t cam_dflags = CAM_DEBUG_NONE;
-#endif
 TUNABLE_INT("kern.cam.dflags", &cam_dflags);
 SYSCTL_UINT(_kern_cam, OID_AUTO, dflags, CTLFLAG_RW,
-	&cam_dflags, 0, "Cam Debug Flags");
-u_int32_t cam_debug_delay;
+	&cam_dflags, 0, "Enabled debug flags");
+u_int32_t cam_debug_delay = CAM_DEBUG_DELAY;
 TUNABLE_INT("kern.cam.debug_delay", &cam_debug_delay);
 SYSCTL_UINT(_kern_cam, OID_AUTO, debug_delay, CTLFLAG_RW,
-	&cam_debug_delay, 0, "Cam Debug Flags");
-#endif
+	&cam_debug_delay, 0, "Delay in us after each debug message");
 
 /* Our boot-time initialization hook */
 static int cam_module_event_handler(module_t, int /*modeventtype_t*/, void *);
@@ -1032,7 +1026,7 @@
 }
 
 void
-xpt_remove_periph(struct cam_periph *periph)
+xpt_remove_periph(struct cam_periph *periph, int topology_lock_held)
 {
 	struct cam_ed *device;
 
@@ -1053,9 +1047,13 @@
 		SLIST_REMOVE(periph_head, periph, cam_periph, periph_links);
 	}
 
-	mtx_lock(&xsoftc.xpt_topo_lock);
+	if (topology_lock_held == 0)
+		mtx_lock(&xsoftc.xpt_topo_lock);
+
 	xsoftc.xpt_generation++;
-	mtx_unlock(&xsoftc.xpt_topo_lock);
+
+	if (topology_lock_held == 0)
+		mtx_unlock(&xsoftc.xpt_topo_lock);
 }
 
 
@@ -1080,6 +1078,9 @@
 	else if (path->device->protocol == PROTO_ATA ||
 	    path->device->protocol == PROTO_SATAPM)
 		ata_print_ident(&path->device->ident_data);
+	else if (path->device->protocol == PROTO_SEMB)
+		semb_print_ident(
+		    (struct sep_identify_data *)&path->device->ident_data);
 	else
 		printf("Unknown protocol device\n");
 	if (bootverbose && path->device->serial_num_len > 0) {
@@ -2469,9 +2470,7 @@
 void
 xpt_action_default(union ccb *start_ccb)
 {
-#ifdef CAMDEBUG
 	char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1];
-#endif
 	struct cam_path *path;
 
 	path = start_ccb->ccb_h.path;
@@ -2902,17 +2901,13 @@
 
 		if ((crs->release_flags & RELSIM_ADJUST_OPENINGS) != 0) {
 
- 			if (INQ_DATA_TQ_ENABLED(&dev->inq_data)) {
-				/* Don't ever go below one opening */
-				if (crs->openings > 0) {
-					xpt_dev_ccbq_resize(path,
-							    crs->openings);
-
-					if (bootverbose) {
-						xpt_print(path,
-						    "tagged openings now %d\n",
-						    crs->openings);
-					}
+			/* Don't ever go below one opening */
+			if (crs->openings > 0) {
+				xpt_dev_ccbq_resize(path, crs->openings);
+				if (bootverbose) {
+					xpt_print(path,
+					    "number of openings is now %d\n",
+					    crs->openings);
 				}
 			}
 		}
@@ -2981,16 +2976,17 @@
 		break;
 	}
 	case XPT_DEBUG: {
-#ifdef CAMDEBUG
-#ifdef CAM_DEBUG_DELAY
-		cam_debug_delay = CAM_DEBUG_DELAY;
-#endif
+		/* Check that all request bits are supported. */
+		if (start_ccb->cdbg.flags & ~(CAM_DEBUG_COMPILE)) {
+			start_ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
+			break;
+		}
+
 		cam_dflags = start_ccb->cdbg.flags;
 		if (cam_dpath != NULL) {
 			xpt_free_path(cam_dpath);
 			cam_dpath = NULL;
 		}
-
 		if (cam_dflags != CAM_DEBUG_NONE) {
 			if (xpt_create_path(&cam_dpath, xpt_periph,
 					    start_ccb->ccb_h.path_id,
@@ -3008,9 +3004,6 @@
 			cam_dpath = NULL;
 			start_ccb->ccb_h.status = CAM_REQ_CMP;
 		}
-#else /* !CAMDEBUG */
-		start_ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
-#endif /* CAMDEBUG */
 		break;
 	}
 	case XPT_FREEZE_QUEUE:
@@ -3227,13 +3220,8 @@
 				("running device %p\n", device));
 
 		drvq = &device->drvq;
-
-#ifdef CAMDEBUG
-		if (drvq->entries <= 0) {
-			panic("xpt_run_dev_allocq: "
-			      "Device on queue without any work to do");
-		}
-#endif
+		KASSERT(drvq->entries > 0, ("xpt_run_dev_allocq: "
+		    "Device on queue without any work to do"));
 		if ((work_ccb = xpt_get_ccb(device)) != NULL) {
 			devq->alloc_openings--;
 			devq->alloc_active++;
@@ -4049,6 +4037,28 @@
 	return (pathid);
 }
 
+static const char *
+xpt_async_string(u_int32_t async_code)
+{
+
+	switch (async_code) {
+	case AC_BUS_RESET: return ("AC_BUS_RESET");
+	case AC_UNSOL_RESEL: return ("AC_UNSOL_RESEL");
+	case AC_SCSI_AEN: return ("AC_SCSI_AEN");
+	case AC_SENT_BDR: return ("AC_SENT_BDR");
+	case AC_PATH_REGISTERED: return ("AC_PATH_REGISTERED");
+	case AC_PATH_DEREGISTERED: return ("AC_PATH_DEREGISTERED");
+	case AC_FOUND_DEVICE: return ("AC_FOUND_DEVICE");
+	case AC_LOST_DEVICE: return ("AC_LOST_DEVICE");
+	case AC_TRANSFER_NEG: return ("AC_TRANSFER_NEG");
+	case AC_INQ_CHANGED: return ("AC_INQ_CHANGED");
+	case AC_GETDEV_CHANGED: return ("AC_GETDEV_CHANGED");
+	case AC_CONTRACT: return ("AC_CONTRACT");
+	case AC_ADVINFO_CHANGED: return ("AC_ADVINFO_CHANGED");
+	}
+	return ("AC_UNKNOWN");
+}
+
 void
 xpt_async(u_int32_t async_code, struct cam_path *path, void *async_arg)
 {
@@ -4057,8 +4067,8 @@
 	struct cam_ed *device, *next_device;
 
 	mtx_assert(path->bus->sim->mtx, MA_OWNED);
-
-	CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_async\n"));
+	CAM_DEBUG(path, CAM_DEBUG_TRACE | CAM_DEBUG_INFO,
+	    ("xpt_async(%s)\n", xpt_async_string(async_code)));
 
 	/*
 	 * Most async events come from a CAM interrupt context.  In
@@ -4332,7 +4342,8 @@
 		TAILQ_INSERT_TAIL(&sim->sim_doneq, &done_ccb->ccb_h,
 		    sim_links.tqe);
 		done_ccb->ccb_h.pinfo.index = CAM_DONEQ_INDEX;
-		if ((sim->flags & (CAM_SIM_ON_DONEQ | CAM_SIM_POLLED)) == 0) {
+		if ((sim->flags & (CAM_SIM_ON_DONEQ | CAM_SIM_POLLED |
+		    CAM_SIM_BATCH)) == 0) {
 			mtx_lock(&cam_simq_lock);
 			first = TAILQ_EMPTY(&cam_simq);
 			TAILQ_INSERT_TAIL(&cam_simq, sim, links);
@@ -4344,6 +4355,25 @@
 	}
 }
 
+void
+xpt_batch_start(struct cam_sim *sim)
+{
+
+	KASSERT((sim->flags & CAM_SIM_BATCH) == 0, ("Batch flag already set"));
+	sim->flags |= CAM_SIM_BATCH;
+}
+
+void
+xpt_batch_done(struct cam_sim *sim)
+{
+
+	KASSERT((sim->flags & CAM_SIM_BATCH) != 0, ("Batch flag was not set"));
+	sim->flags &= ~CAM_SIM_BATCH;
+	if (!TAILQ_EMPTY(&sim->sim_doneq) &&
+	    (sim->flags & CAM_SIM_ON_DONEQ) == 0)
+		camisr_runqueue(&sim->sim_doneq);
+}
+
 union ccb *
 xpt_alloc_ccb()
 {
@@ -4696,6 +4726,7 @@
 		newopenings = min(device->maxtags,
 				  sim->max_tagged_dev_openings);
 	xpt_dev_ccbq_resize(path, newopenings);
+	xpt_async(AC_GETDEV_CHANGED, path, NULL);
 	xpt_setup_ccb(&crs.ccb_h, path, CAM_PRIORITY_NORMAL);
 	crs.ccb_h.func_code = XPT_REL_SIMQ;
 	crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY;
@@ -4720,6 +4751,7 @@
 	xpt_freeze_devq(path, /*count*/1);
 	device->inq_flags &= ~SID_CmdQue;
 	xpt_dev_ccbq_resize(path, sim->max_dev_openings);
+	xpt_async(AC_GETDEV_CHANGED, path, NULL);
 	xpt_setup_ccb(&crs.ccb_h, path, CAM_PRIORITY_NORMAL);
 	crs.ccb_h.func_code = XPT_REL_SIMQ;
 	crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY;
@@ -4744,9 +4776,7 @@
 	 * Now that interrupts are enabled, go find our devices
 	 */
 
-#ifdef CAMDEBUG
-	/* Setup debugging flags and path */
-#ifdef CAM_DEBUG_BUS
+	/* Setup debugging path */
 	if (cam_dflags != CAM_DEBUG_NONE) {
 		/*
 		 * Locking is specifically omitted here.  No SIMs have
@@ -4763,10 +4793,6 @@
 		}
 	} else
 		cam_dpath = NULL;
-#else /* !CAM_DEBUG_BUS */
-	cam_dpath = NULL;
-#endif /* CAM_DEBUG_BUS */
-#endif /* CAMDEBUG */
 
 	periphdriver_init(1);
 	xpt_hold_boot();
@@ -4839,7 +4865,8 @@
 	 * attached.  For any devices like that, announce the
 	 * passthrough driver so the user will see something.
 	 */
-	xpt_for_all_devices(xptpassannouncefunc, NULL);
+	if (!bootverbose)
+		xpt_for_all_devices(xptpassannouncefunc, NULL);
 
 	/* Release our hook so that the boot can continue. */
 	config_intrhook_disestablish(xsoftc.xpt_config_hook);
@@ -4978,8 +5005,8 @@
 		while ((sim = TAILQ_FIRST(&queue)) != NULL) {
 			TAILQ_REMOVE(&queue, sim, links);
 			CAM_SIM_LOCK(sim);
+			camisr_runqueue(&sim->sim_doneq);
 			sim->flags &= ~CAM_SIM_ON_DONEQ;
-			camisr_runqueue(&sim->sim_doneq);
 			CAM_SIM_UNLOCK(sim);
 		}
 		mtx_lock(&cam_simq_lock);
@@ -5042,10 +5069,16 @@
 			ccb_h->path->bus->sim->devq->send_openings++;
 			runq = TRUE;
 
+			if (((dev->flags & CAM_DEV_REL_ON_QUEUE_EMPTY) != 0
+			  && (dev->ccbq.dev_active == 0))) {
+				dev->flags &= ~CAM_DEV_REL_ON_QUEUE_EMPTY;
+				xpt_release_devq(ccb_h->path, /*count*/1,
+						 /*run_queue*/FALSE);
+			}
+
 			if (((dev->flags & CAM_DEV_REL_ON_COMPLETE) != 0
-			  && (ccb_h->status&CAM_STATUS_MASK) != CAM_REQUEUE_REQ)
-			 || ((dev->flags & CAM_DEV_REL_ON_QUEUE_EMPTY) != 0
-			  && (dev->ccbq.dev_active == 0))) {
+			  && (ccb_h->status&CAM_STATUS_MASK) != CAM_REQUEUE_REQ)) {
+				dev->flags &= ~CAM_DEV_REL_ON_COMPLETE;
 				xpt_release_devq(ccb_h->path, /*count*/1,
 						 /*run_queue*/FALSE);
 			}
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/cam_xpt.h
--- a/head/sys/cam/cam_xpt.h	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/cam_xpt.h	Wed Jul 25 16:45:04 2012 +0300
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/sys/cam/cam_xpt.h 224806 2011-08-12 20:09:38Z mjacob $
+ * $FreeBSD: head/sys/cam/cam_xpt.h 236712 2012-06-07 10:05:51Z mav $
  */
 
 #ifndef _CAM_CAM_XPT_H
@@ -63,28 +63,6 @@
 SLIST_HEAD(async_list, async_node);
 SLIST_HEAD(periph_list, cam_periph);
 
-#if defined(CAM_DEBUG_FLAGS) && !defined(CAMDEBUG)
-#error "You must have options CAMDEBUG to use options CAM_DEBUG_FLAGS"
-#endif
-
-/*
- * In order to enable the CAM_DEBUG_* options, the user must have CAMDEBUG
- * enabled.  Also, the user must have either none, or all of CAM_DEBUG_BUS,
- * CAM_DEBUG_TARGET, and CAM_DEBUG_LUN specified.
- */
-#if defined(CAM_DEBUG_BUS) || defined(CAM_DEBUG_TARGET) \
-    || defined(CAM_DEBUG_LUN)
-#ifdef CAMDEBUG
-#if !defined(CAM_DEBUG_BUS) || !defined(CAM_DEBUG_TARGET) \
-    || !defined(CAM_DEBUG_LUN)
-#error "You must define all or none of CAM_DEBUG_BUS, CAM_DEBUG_TARGET \
-        and CAM_DEBUG_LUN"
-#endif /* !CAM_DEBUG_BUS || !CAM_DEBUG_TARGET || !CAM_DEBUG_LUN */
-#else /* !CAMDEBUG */
-#error "You must use options CAMDEBUG if you use the CAM_DEBUG_* options"
-#endif /* CAMDEBUG */
-#endif /* CAM_DEBUG_BUS || CAM_DEBUG_TARGET || CAM_DEBUG_LUN */
-
 void			xpt_action(union ccb *new_ccb);
 void			xpt_action_default(union ccb *new_ccb);
 union ccb		*xpt_alloc_ccb(void);
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/cam_xpt_periph.h
--- a/head/sys/cam/cam_xpt_periph.h	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/cam_xpt_periph.h	Wed Jul 25 16:45:04 2012 +0300
@@ -27,7 +27,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/cam/cam_xpt_periph.h 237328 2012-06-20 17:08:00Z ken $
  */
 
 #ifndef _CAM_CAM_XPT_PERIPH_H
@@ -42,7 +42,8 @@
 void		xpt_release_ccb(union ccb *released_ccb);
 void		xpt_schedule(struct cam_periph *perph, u_int32_t new_priority);
 int32_t		xpt_add_periph(struct cam_periph *periph);
-void		xpt_remove_periph(struct cam_periph *periph);
+void		xpt_remove_periph(struct cam_periph *periph,
+				  int topology_lock_held);
 void		xpt_announce_periph(struct cam_periph *periph,
 				    char *announce_string);
 #endif
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/cam_xpt_sim.h
--- a/head/sys/cam/cam_xpt_sim.h	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/cam_xpt_sim.h	Wed Jul 25 16:45:04 2012 +0300
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/cam/cam_xpt_sim.h 235333 2012-05-12 13:55:36Z mav $
  */
 
 #ifndef _CAM_CAM_XPT_SIM_H
@@ -51,6 +51,8 @@
 		    u_int count, int run_queue);
 int		xpt_sim_opened(struct cam_sim *sim);
 void		xpt_done(union ccb *done_ccb);
+void		xpt_batch_start(struct cam_sim *sim);
+void		xpt_batch_done(struct cam_sim *sim);
 #endif
 
 #endif /* _CAM_CAM_XPT_SIM_H */
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/ctl/ctl.c
--- a/head/sys/cam/ctl/ctl.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/ctl/ctl.c	Wed Jul 25 16:45:04 2012 +0300
@@ -42,7 +42,7 @@
 #define _CTL_C
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/cam/ctl/ctl.c 233963 2012-04-06 22:23:13Z ken $");
+__FBSDID("$FreeBSD: head/sys/cam/ctl/ctl.c 237726 2012-06-28 19:39:30Z ken $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -308,7 +308,6 @@
 	/*aen_holdoff_period*/{0, 0}
 };
 
-SYSCTL_NODE(_kern_cam, OID_AUTO, ctl, CTLFLAG_RD, 0, "CAM Target Layer");
 
 /*
  * XXX KDM move these into the softc.
@@ -318,7 +317,12 @@
 static uint8_t ctl_pause_rtr;
 static int     ctl_is_single;
 static int     index_to_aps_page;
-
+int	   ctl_disable = 0;
+
+SYSCTL_NODE(_kern_cam, OID_AUTO, ctl, CTLFLAG_RD, 0, "CAM Target Layer");
+SYSCTL_INT(_kern_cam_ctl, OID_AUTO, disable, CTLFLAG_RDTUN, &ctl_disable, 0,
+	   "Disable CTL");
+TUNABLE_INT("kern.cam.ctl.disable", &ctl_disable);
 
 /*
  * Serial number (0x80), device id (0x83), and supported pages (0x00)
@@ -949,6 +953,10 @@
 	ctl_pause_rtr = 0;
         rcv_sync_msg = 0;
 
+	/* If we're disabled, don't initialize. */
+	if (ctl_disable != 0)
+		return;
+
 	control_softc = malloc(sizeof(*control_softc), M_DEVBUF, M_WAITOK);
 	softc = control_softc;
 
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/ctl/ctl_backend.c
--- a/head/sys/cam/ctl/ctl_backend.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/ctl/ctl_backend.c	Wed Jul 25 16:45:04 2012 +0300
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/cam/ctl/ctl_backend.c 233963 2012-04-06 22:23:13Z ken $");
+__FBSDID("$FreeBSD: head/sys/cam/ctl/ctl_backend.c 237726 2012-06-28 19:39:30Z ken $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -62,6 +62,7 @@
 #include <cam/ctl/ctl_debug.h>
 
 extern struct ctl_softc *control_softc;
+extern int ctl_disable;
 
 int
 ctl_backend_register(struct ctl_backend_driver *be)
@@ -71,6 +72,10 @@
 
 	ctl_softc = control_softc;
 
+	/* Don't continue if CTL is disabled */
+	if (ctl_disable != 0)
+		return (0);
+
 	mtx_lock(&ctl_softc->ctl_lock);
 	/*
 	 * Sanity check, make sure this isn't a duplicate registration.
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/ctl/ctl_frontend_cam_sim.c
--- a/head/sys/cam/ctl/ctl_frontend_cam_sim.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/ctl/ctl_frontend_cam_sim.c	Wed Jul 25 16:45:04 2012 +0300
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/cam/ctl/ctl_frontend_cam_sim.c 231092 2012-02-06 18:11:00Z emaste $");
+__FBSDID("$FreeBSD: head/sys/cam/ctl/ctl_frontend_cam_sim.c 237726 2012-06-28 19:39:30Z ken $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -119,6 +119,7 @@
  * amount of SCSI sense data that we will report to CAM.
  */
 static int cfcs_max_sense = sizeof(struct scsi_sense_data);
+extern int ctl_disable;
 
 SYSINIT(cfcs_init, SI_SUB_CONFIGURE, SI_ORDER_FOURTH, cfcs_init, NULL);
 SYSCTL_NODE(_kern_cam, OID_AUTO, ctl2cam, CTLFLAG_RD, 0,
@@ -138,6 +139,10 @@
 #endif
 	int retval;
 
+	/* Don't continue if CTL is disabled */
+	if (ctl_disable != 0)
+		return (0);
+
 	softc = &cfcs_softc;
 	retval = 0;
 	bzero(softc, sizeof(*softc));
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/ctl/ctl_frontend_internal.c
--- a/head/sys/cam/ctl/ctl_frontend_internal.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/ctl/ctl_frontend_internal.c	Wed Jul 25 16:45:04 2012 +0300
@@ -48,7 +48,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/cam/ctl/ctl_frontend_internal.c 233963 2012-04-06 22:23:13Z ken $");
+__FBSDID("$FreeBSD: head/sys/cam/ctl/ctl_frontend_internal.c 237726 2012-06-28 19:39:30Z ken $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -187,6 +187,7 @@
 MALLOC_DEFINE(M_CTL_CFI, "ctlcfi", "CTL CFI");
 
 static struct cfi_softc fetd_internal_softc;
+extern int ctl_disable;
 
 void cfi_init(void);
 void cfi_shutdown(void) __unused;
@@ -231,6 +232,10 @@
 
 	retval = 0;
 
+	/* If we're disabled, don't initialize */
+	if (ctl_disable != 0)
+		return;
+
 	if (sizeof(struct cfi_lun_io) > CTL_PORT_PRIV_SIZE) {
 		printf("%s: size of struct cfi_lun_io %zd > "
 		       "CTL_PORT_PRIV_SIZE %d\n", __func__,
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/ctl/scsi_ctl.c
--- a/head/sys/cam/ctl/scsi_ctl.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/ctl/scsi_ctl.c	Wed Jul 25 16:45:04 2012 +0300
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/cam/ctl/scsi_ctl.c 230033 2012-01-12 22:08:33Z ken $");
+__FBSDID("$FreeBSD: head/sys/cam/ctl/scsi_ctl.c 237726 2012-06-28 19:39:30Z ken $");
 
 #include <sys/param.h>
 #include <sys/queue.h>
@@ -227,12 +227,17 @@
 PERIPHDRIVER_DECLARE(ctl, ctlfe_driver);
 
 extern struct ctl_softc *control_softc;
+extern int ctl_disable;
 
 int
 ctlfeinitialize(void)
 {
 	cam_status status;
 
+	/* Don't initialize if we're disabled */
+	if (ctl_disable != 0)
+		return (0);
+
 	STAILQ_INIT(&ctlfe_softc_list);
 
 	mtx_init(&ctlfe_list_mtx, ctlfe_mtx_desc, NULL, MTX_DEF);
@@ -263,6 +268,10 @@
 {
 	cam_status status;
 
+	/* Don't initialize if we're disabled */
+	if (ctl_disable != 0)
+		return;
+
 	STAILQ_INIT(&ctlfe_softc_list);
 
 	mtx_init(&ctlfe_list_mtx, ctlfe_mtx_desc, NULL, MTX_DEF);
@@ -490,7 +499,7 @@
 
 			dev_chg = (struct ac_device_changed *)ac->contract_data;
 
-			printf("%s: WWPN %#jx port %u path %u target %u %s\n",
+			printf("%s: WWPN %#jx port 0x%06x path %u target %u %s\n",
 			       __func__, dev_chg->wwpn, dev_chg->port,
 			       xpt_path_path_id(path), dev_chg->target,
 			       (dev_chg->arrived == 0) ?  "left" : "arrived");
@@ -558,7 +567,6 @@
 	
 	TAILQ_INIT(&softc->work_queue);
 	softc->periph = periph;
-	softc->parent_softc = bus_softc;
 
 	callout_init_mtx(&softc->dma_callout, sim->mtx, /*flags*/ 0);
 	periph->softc = softc;
@@ -582,7 +590,7 @@
 		union ccb *new_ccb;
 
 		new_ccb = (union ccb *)malloc(sizeof(*new_ccb), M_CTLFE,
-					      M_NOWAIT);
+					      M_ZERO|M_NOWAIT);
 		if (new_ccb == NULL) {
 			status = CAM_RESRC_UNAVAIL;
 			break;
@@ -616,7 +624,7 @@
 		union ccb *new_ccb;
 
 		new_ccb = (union ccb *)malloc(sizeof(*new_ccb), M_CTLFE,
-					      M_NOWAIT);
+					      M_ZERO|M_NOWAIT);
 		if (new_ccb == NULL) {
 			status = CAM_RESRC_UNAVAIL;
 			break;
@@ -628,12 +636,22 @@
 		xpt_action(new_ccb);
 		softc->inots_sent++;
 		status = new_ccb->ccb_h.status;
-		if (status != CAM_REQ_INPROG) {
-			free(new_ccb, M_CTLFE);
+		if ((status & CAM_STATUS_MASK) != CAM_REQ_INPROG) {
+			/*
+			 * Note that we don't free the CCB here.  If the
+			 * status is not CAM_REQ_INPROG, then we're
+			 * probably talking to a SIM that says it is
+			 * target-capable but doesn't support the 
+			 * XPT_IMMEDIATE_NOTIFY CCB.  i.e. it supports the
+			 * older API.  In that case, it'll call xpt_done()
+			 * on the CCB, and we need to free it in our done
+			 * routine as a result.
+			 */
 			break;
 		}
 	}
-	if (i == 0) {
+	if ((i == 0)
+	 || (status != CAM_REQ_INPROG)) {
 		xpt_print(periph->path, "%s: could not allocate immediate "
 			  "notify CCBs, status 0x%x\n", __func__, status);
 		return (CAM_REQ_CMP_ERR);
@@ -1460,12 +1478,29 @@
 				 */
 				send_ctl_io = 0;
 				break;
+			case CAM_REQ_INVALID:
+			case CAM_PROVIDE_FAIL:
 			default:
-				xpt_print(periph->path, "%s: "
-					  "unsupported CAM status 0x%x\n", 
-					  __func__, status);
-				send_ctl_io = 0;
-				break;
+				/*
+				 * We should only get here if we're talking
+				 * to a talking to a SIM that is target
+				 * capable but supports the old API.  In
+				 * that case, we need to just free the CCB.
+				 * If we actually send a notify acknowledge,
+				 * it will send that back with an error as
+				 * well.
+				 */
+
+				if ((status != CAM_REQ_INVALID)
+				 && (status != CAM_PROVIDE_FAIL))
+					xpt_print(periph->path, "%s: "
+						  "unsupported CAM status "
+						  "0x%x\n", __func__, status);
+
+				ctl_free_io(io);
+				ctlfe_free_ccb(periph, done_ccb);
+
+				return;
 			}
 			if (send_ctl_io != 0) {
 				ctl_queue(io);
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/scsi/scsi_all.c
--- a/head/sys/cam/scsi/scsi_all.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/scsi/scsi_all.c	Wed Jul 25 16:45:04 2012 +0300
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_all.c 230590 2012-01-26 18:09:28Z ken $");
+__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_all.c 238596 2012-07-18 12:41:09Z mav $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -768,7 +768,7 @@
 	 *
 	 * SCSI ASC/ASCQ Assignments
 	 * Numeric Sorted Listing
-	 * as of  7/29/08
+	 * as of  5/20/12
 	 *
 	 * D - DIRECT ACCESS DEVICE (SBC-2)                   device column key
 	 * .T - SEQUENTIAL ACCESS DEVICE (SSC)               -------------------
@@ -854,6 +854,12 @@
 	/* DT   R MAEBKV  */
 	{ SST(0x00, 0x1E, SS_RDEF,	/* XXX TBD */
 	    "Conflicting SA creation request") },
+	/* DT        B    */
+	{ SST(0x00, 0x1F, SS_RDEF,	/* XXX TBD */
+	    "Logical unit transitioning to another power condition") },
+	/* DT P      B    */
+	{ SST(0x00, 0x20, SS_RDEF,	/* XXX TBD */
+	    "Extended copy information available") },
 	/* D   W O   BK   */
 	{ SST(0x01, 0x00, SS_RDEF,
 	    "No index/sector signal") },
@@ -923,6 +929,33 @@
 	/* DT   R MAEBKV  */
 	{ SST(0x04, 0x13, SS_RDEF,	/* XXX TBD */
 	    "Logical unit not ready, SA creation in progress") },
+	/* D         B    */
+	{ SST(0x04, 0x14, SS_RDEF,	/* XXX TBD */
+	    "Logical unit not ready, space allocation in progress") },
+	/*        M       */
+	{ SST(0x04, 0x15, SS_RDEF,	/* XXX TBD */
+	    "Logical unit not ready, robotics disabled") },
+	/*        M       */
+	{ SST(0x04, 0x16, SS_RDEF,	/* XXX TBD */
+	    "Logical unit not ready, configuration required") },
+	/*        M       */
+	{ SST(0x04, 0x17, SS_RDEF,	/* XXX TBD */
+	    "Logical unit not ready, calibration required") },
+	/*        M       */
+	{ SST(0x04, 0x18, SS_RDEF,	/* XXX TBD */
+	    "Logical unit not ready, a door is open") },
+	/*        M       */
+	{ SST(0x04, 0x19, SS_RDEF,	/* XXX TBD */
+	    "Logical unit not ready, operating in sequential mode") },
+	/* DT        B    */
+	{ SST(0x04, 0x1A, SS_RDEF,	/* XXX TBD */
+	    "Logical unit not ready, START/STOP UNIT command in progress") },
+	/* D         B    */
+	{ SST(0x04, 0x1B, SS_RDEF,	/* XXX TBD */
+	    "Logical unit not ready, sanitize in progress") },
+	/* DT     MAEB    */
+	{ SST(0x04, 0x1C, SS_RDEF,	/* XXX TBD */
+	    "Logical unit not ready, additional power use not yet granted") },
 	/* DTL WROMAEBKVF */
 	{ SST(0x05, 0x00, SS_RDEF,
 	    "Logical unit does not respond to selection") },
@@ -989,6 +1022,12 @@
 	/* DTLPWROMAEBKVF */
 	{ SST(0x0B, 0x07, SS_RDEF,	/* XXX TBD */
 	    "Warning - degraded power to non-volatile cache") },
+	/* DTLPWROMAEBKVF */
+	{ SST(0x0B, 0x08, SS_RDEF,	/* XXX TBD */
+	    "Warning - power loss expected") },
+	/* D              */
+	{ SST(0x0B, 0x09, SS_RDEF,	/* XXX TBD */
+	    "Warning - device statistics notification available") },
 	/*  T   R         */
 	{ SST(0x0C, 0x00, SS_RDEF,
 	    "Write error") },
@@ -1031,6 +1070,9 @@
 	/* DTLPWRO AEBKVF */
 	{ SST(0x0C, 0x0D, SS_RDEF,	/* XXX TBD */
 	    "Write error - not enough unsolicited data") },
+	/* DT  W O   BK   */
+	{ SST(0x0C, 0x0E, SS_RDEF,	/* XXX TBD */
+	    "Multiple write errors") },
 	/*      R         */
 	{ SST(0x0C, 0x0F, SS_RDEF,	/* XXX TBD */
 	    "Defects in error window") },
@@ -1076,6 +1118,12 @@
 	/* DT  W O        */
 	{ SST(0x10, 0x03, SS_RDEF,	/* XXX TBD */
 	    "Logical block reference tag check failed") },
+	/*  T             */
+	{ SST(0x10, 0x04, SS_RDEF,	/* XXX TBD */
+	    "Logical block protection error on recovered buffer data") },
+	/*  T             */
+	{ SST(0x10, 0x05, SS_RDEF,	/* XXX TBD */
+	    "Logical block protection method error") },
 	/* DT  WRO   BK   */
 	{ SST(0x11, 0x00, SS_FATAL|EIO,
 	    "Unrecovered read error") },
@@ -1280,6 +1328,9 @@
 	/* DT  WRO   BK   */
 	{ SST(0x1D, 0x00, SS_FATAL,
 	    "Miscompare during verify operation") },
+	/* D         B    */
+	{ SST(0x1D, 0x01, SS_RDEF,	/* XXX TBD */
+	    "Miscomparable verify of unmapped LBA") },
 	/* D   W O   BK   */
 	{ SST(0x1E, 0x00, SS_NOP | SSQ_PRINT_SENSE,
 	    "Recovered ID with ECC correction") },
@@ -1322,6 +1373,9 @@
 	/* DT PWROMAEBK   */
 	{ SST(0x20, 0x0B, SS_RDEF,	/* XXX TBD */
 	    "Access denied - ACL LUN conflict") },
+	/*  T             */
+	{ SST(0x20, 0x0C, SS_FATAL | EINVAL,
+	    "Illegal command when not in append-only mode") },
 	/* DT  WRO   BK   */
 	{ SST(0x21, 0x00, SS_FATAL | EINVAL,
 	    "Logical block address out of range") },
@@ -1337,6 +1391,39 @@
 	/* D              */
 	{ SST(0x22, 0x00, SS_FATAL | EINVAL,
 	    "Illegal function (use 20 00, 24 00, or 26 00)") },
+	/* DT P      B    */
+	{ SST(0x23, 0x00, SS_RDEF,	/* XXX TBD */
+	    "Invalid token operation, cause not reportable") },
+	/* DT P      B    */
+	{ SST(0x23, 0x01, SS_RDEF,	/* XXX TBD */
+	    "Invalid token operation, unsupported token type") },
+	/* DT P      B    */
+	{ SST(0x23, 0x02, SS_RDEF,	/* XXX TBD */
+	    "Invalid token operation, remote token usage not supported") },
+	/* DT P      B    */
+	{ SST(0x23, 0x03, SS_RDEF,	/* XXX TBD */
+	    "Invalid token operation, remote ROD token creation not supported") },
+	/* DT P      B    */
+	{ SST(0x23, 0x04, SS_RDEF,	/* XXX TBD */
+	    "Invalid token operation, token unknown") },
+	/* DT P      B    */
+	{ SST(0x23, 0x05, SS_RDEF,	/* XXX TBD */
+	    "Invalid token operation, token corrupt") },
+	/* DT P      B    */
+	{ SST(0x23, 0x06, SS_RDEF,	/* XXX TBD */
+	    "Invalid token operation, token revoked") },
+	/* DT P      B    */
+	{ SST(0x23, 0x07, SS_RDEF,	/* XXX TBD */
+	    "Invalid token operation, token expired") },
+	/* DT P      B    */
+	{ SST(0x23, 0x08, SS_RDEF,	/* XXX TBD */
+	    "Invalid token operation, token cancelled") },
+	/* DT P      B    */
+	{ SST(0x23, 0x09, SS_RDEF,	/* XXX TBD */
+	    "Invalid token operation, token deleted") },
+	/* DT P      B    */
+	{ SST(0x23, 0x0A, SS_RDEF,	/* XXX TBD */
+	    "Invalid token operation, invalid token length") },
 	/* DTLPWROMAEBKVF */
 	{ SST(0x24, 0x00, SS_FATAL | EINVAL,
 	    "Invalid field in CDB") },
@@ -1445,6 +1532,9 @@
 	/*      R       F */
 	{ SST(0x27, 0x06, SS_RDEF,	/* XXX TBD */
 	    "Conditional write protect") },
+	/* D         B    */
+	{ SST(0x27, 0x07, SS_RDEF,	/* XXX TBD */
+	    "Space allocation failed write protect") },
 	/* DTLPWROMAEBKVF */
 	{ SST(0x28, 0x00, SS_FATAL | ENXIO,
 	    "Not ready to ready change, medium may have changed") },
@@ -1543,6 +1633,9 @@
 	/* DT   R MAEBKV  */
 	{ SST(0x2A, 0x14, SS_RDEF,	/* XXX TBD */
 	    "SA creation capabilities data has changed") },
+	/*  T     M    V  */
+	{ SST(0x2A, 0x15, SS_RDEF,	/* XXX TBD */
+	    "Medium removal prevention preempted") },
 	/* DTLPWRO    K   */
 	{ SST(0x2B, 0x00, SS_RDEF,
 	    "Copy cannot execute since host cannot disconnect") },
@@ -1582,6 +1675,9 @@
 	/*  T             */
 	{ SST(0x2C, 0x0B, SS_RDEF,	/* XXX TBD */
 	    "Not reserved") },
+	/* D              */
+	{ SST(0x2C, 0x0C, SS_RDEF,	/* XXX TBD */
+	    "ORWRITE generation does not match") },
 	/*  T             */
 	{ SST(0x2D, 0x00, SS_RDEF,
 	    "Overwrite error on update in place") },
@@ -1645,6 +1741,9 @@
 	/*        M       */
 	{ SST(0x30, 0x12, SS_RDEF,	/* XXX TBD */
 	    "Incompatible volume qualifier") },
+	/*        M       */
+	{ SST(0x30, 0x13, SS_RDEF,	/* XXX TBD */
+	    "Cleaning volume expired") },
 	/* DT  WRO   BK   */
 	{ SST(0x31, 0x00, SS_RDEF,
 	    "Medium format corrupted") },
@@ -1654,6 +1753,9 @@
 	/*      R         */
 	{ SST(0x31, 0x02, SS_RDEF,	/* XXX TBD */
 	    "Zoned formatting failed due to spare linking") },
+	/* D         B    */
+	{ SST(0x31, 0x03, SS_RDEF,	/* XXX TBD */
+	    "SANITIZE command failed") },
 	/* D   W O   BK   */
 	{ SST(0x32, 0x00, SS_RDEF,
 	    "No defect spare location available") },
@@ -1702,6 +1804,9 @@
 	/*           B    */
 	{ SST(0x38, 0x06, SS_RDEF,	/* XXX TBD */
 	    "ESN - device busy class event") },
+	/* D              */
+	{ SST(0x38, 0x07, SS_RDEF,	/* XXX TBD */
+	    "Thin provisioning soft threshold reached") },
 	/* DTL WROMAE K   */
 	{ SST(0x39, 0x00, SS_RDEF,
 	    "Saving parameters not supported") },
@@ -1801,6 +1906,9 @@
 	/*        M       */
 	{ SST(0x3B, 0x1B, SS_RDEF,	/* XXX TBD */
 	    "Data transfer device inserted") },
+	/*  T             */
+	{ SST(0x3B, 0x1C, SS_RDEF,	/* XXX TBD */
+	    "Too many logical objects on partition to support operation") },
 	/* DTLPWROMAE K   */
 	{ SST(0x3D, 0x00, SS_RDEF,
 	    "Invalid bits in IDENTIFY message") },
@@ -1904,6 +2012,9 @@
 	/* DTLPWROMAEBKVF */
 	{ SST(0x44, 0x00, SS_RDEF,
 	    "Internal target failure") },
+	/* DT P   MAEBKVF */
+	{ SST(0x44, 0x01, SS_RDEF,	/* XXX TBD */
+	    "Persistent reservation information lost") },
 	/* DT        B    */
 	{ SST(0x44, 0x71, SS_RDEF,	/* XXX TBD */
 	    "ATA device failed set features") },
@@ -1967,6 +2078,27 @@
 	/* DT PWROMAEBK   */
 	{ SST(0x4B, 0x06, SS_RDEF,	/* XXX TBD */
 	    "Initiator response timeout") },
+	/* DT PWROMAEBK F */
+	{ SST(0x4B, 0x07, SS_RDEF,	/* XXX TBD */
+	    "Connection lost") },
+	/* DT PWROMAEBK F */
+	{ SST(0x4B, 0x08, SS_RDEF,	/* XXX TBD */
+	    "Data-in buffer overflow - data buffer size") },
+	/* DT PWROMAEBK F */
+	{ SST(0x4B, 0x09, SS_RDEF,	/* XXX TBD */
+	    "Data-in buffer overflow - data buffer descriptor area") },
+	/* DT PWROMAEBK F */
+	{ SST(0x4B, 0x0A, SS_RDEF,	/* XXX TBD */
+	    "Data-in buffer error") },
+	/* DT PWROMAEBK F */
+	{ SST(0x4B, 0x0B, SS_RDEF,	/* XXX TBD */
+	    "Data-out buffer overflow - data buffer size") },
+	/* DT PWROMAEBK F */
+	{ SST(0x4B, 0x0C, SS_RDEF,	/* XXX TBD */
+	    "Data-out buffer overflow - data buffer descriptor area") },
+	/* DT PWROMAEBK F */
+	{ SST(0x4B, 0x0D, SS_RDEF,	/* XXX TBD */
+	    "Data-out buffer error") },
 	/* DTLPWROMAEBKVF */
 	{ SST(0x4C, 0x00, SS_RDEF,
 	    "Logical unit failed self-configuration") },
@@ -2012,6 +2144,18 @@
 	/*  T             */
 	{ SST(0x53, 0x04, SS_RDEF,	/* XXX TBD */
 	    "Medium thread or unthread failure") },
+	/*        M       */
+	{ SST(0x53, 0x05, SS_RDEF,	/* XXX TBD */
+	    "Volume identifier invalid") },
+	/*  T             */
+	{ SST(0x53, 0x06, SS_RDEF,	/* XXX TBD */
+	    "Volume identifier missing") },
+	/*        M       */
+	{ SST(0x53, 0x07, SS_RDEF,	/* XXX TBD */
+	    "Duplicate volume identifier") },
+	/*        M       */
+	{ SST(0x53, 0x08, SS_RDEF,	/* XXX TBD */
+	    "Element status unknown") },
 	/*    P           */
 	{ SST(0x54, 0x00, SS_RDEF,
 	    "SCSI to host system interface failure") },
@@ -2048,6 +2192,15 @@
 	/*        M       */
 	{ SST(0x55, 0x0A, SS_RDEF,	/* XXX TBD */
 	    "Data currently unavailable") },
+	/* DTLPWROMAEBKVF */
+	{ SST(0x55, 0x0B, SS_RDEF,	/* XXX TBD */
+	    "Insufficient power for operation") },
+	/* DT P      B    */
+	{ SST(0x55, 0x0C, SS_RDEF,	/* XXX TBD */
+	    "Insufficient resources to create ROD") },
+	/* DT P      B    */
+	{ SST(0x55, 0x0D, SS_RDEF,	/* XXX TBD */
+	    "Insufficient resources to create ROD token") },
 	/*      R         */
 	{ SST(0x57, 0x00, SS_RDEF,
 	    "Unable to recover table-of-contents") },
@@ -2354,6 +2507,24 @@
 	/* DTLPWRO A  K   */
 	{ SST(0x5E, 0x04, SS_RDEF,
 	    "Standby condition activated by command") },
+	/* DTLPWRO A  K   */
+	{ SST(0x5E, 0x05, SS_RDEF,
+	    "Idle-B condition activated by timer") },
+	/* DTLPWRO A  K   */
+	{ SST(0x5E, 0x06, SS_RDEF,
+	    "Idle-B condition activated by command") },
+	/* DTLPWRO A  K   */
+	{ SST(0x5E, 0x07, SS_RDEF,
+	    "Idle-C condition activated by timer") },
+	/* DTLPWRO A  K   */
+	{ SST(0x5E, 0x08, SS_RDEF,
+	    "Idle-C condition activated by command") },
+	/* DTLPWRO A  K   */
+	{ SST(0x5E, 0x09, SS_RDEF,
+	    "Standby-Y condition activated by timer") },
+	/* DTLPWRO A  K   */
+	{ SST(0x5E, 0x0A, SS_RDEF,
+	    "Standby-Y condition activated by command") },
 	/*           B    */
 	{ SST(0x5E, 0x41, SS_RDEF,	/* XXX TBD */
 	    "Power state change to active") },
@@ -2834,11 +3005,10 @@
 	int error_code, sense_key, asc, ascq;
 	scsi_sense_action action;
 
-	scsi_extract_sense_len(&csio->sense_data, csio->sense_len -
-			       csio->sense_resid, &error_code,
-			       &sense_key, &asc, &ascq, /*show_errors*/ 1);
-
-	if ((error_code == SSD_DEFERRED_ERROR)
+	if (!scsi_extract_sense_ccb((union ccb *)csio,
+	    &error_code, &sense_key, &asc, &ascq)) {
+		action = SS_RETRY | SSQ_DECREMENT_COUNT | SSQ_PRINT_SENSE | EIO;
+	} else if ((error_code == SSD_DEFERRED_ERROR)
 	 || (error_code == SSD_DESC_DEFERRED_ERROR)) {
 		/*
 		 * XXX dufault at FreeBSD.org
@@ -2901,11 +3071,17 @@
 					  SSQ_PRINT_SENSE;
 			}
 		}
+		if ((action & SS_MASK) >= SS_START &&
+		    (sense_flags & SF_NO_RECOVERY)) {
+			action &= ~SS_MASK;
+			action |= SS_FAIL;
+		} else if ((action & SS_MASK) == SS_RETRY &&
+		    (sense_flags & SF_NO_RETRY)) {
+			action &= ~SS_MASK;
+			action |= SS_FAIL;
+		}
+
 	}
-#ifdef _KERNEL
-	if (bootverbose)
-		sense_flags |= SF_PRINT_ALWAYS;
-#endif
 	if ((sense_flags & SF_PRINT_ALWAYS) != 0)
 		action |= SSQ_PRINT_SENSE;
 	else if ((sense_flags & SF_NO_PRINT) != 0)
@@ -3059,6 +3235,10 @@
 					    sizeof(cdb_str)));
 	}
 
+#ifdef _KERNEL
+	xpt_free_ccb((union ccb *)cgd);
+#endif
+
 	return(0);
 }
 
@@ -4138,9 +4318,9 @@
 		     struct scsi_inquiry_data *inq_data,
 		     struct scsi_sense_desc_header *header)
 {
-	int i, found;
-
-	for (i = 0, found = 0; i < (sizeof(scsi_sense_printers) /
+	int i;
+
+	for (i = 0; i < (sizeof(scsi_sense_printers) /
 	     sizeof(scsi_sense_printers[0])); i++) {
 		struct scsi_sense_desc_printer *printer;
 
@@ -4612,6 +4792,36 @@
 }
 
 /*
+ * Extract basic sense information from SCSI I/O CCB structure.
+ */
+int
+scsi_extract_sense_ccb(union ccb *ccb,
+    int *error_code, int *sense_key, int *asc, int *ascq)
+{
+	struct scsi_sense_data *sense_data;
+
+	/* Make sure there are some sense data we can access. */
+	if (ccb->ccb_h.func_code != XPT_SCSI_IO ||
+	    (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_SCSI_STATUS_ERROR ||
+	    (ccb->csio.scsi_status != SCSI_STATUS_CHECK_COND) ||
+	    (ccb->ccb_h.status & CAM_AUTOSNS_VALID) == 0 ||
+	    (ccb->ccb_h.flags & CAM_SENSE_PHYS))
+		return (0);
+
+	if (ccb->ccb_h.flags & CAM_SENSE_PTR)
+		bcopy(&ccb->csio.sense_data, &sense_data,
+		    sizeof(struct scsi_sense_data *));
+	else
+		sense_data = &ccb->csio.sense_data;
+	scsi_extract_sense_len(sense_data,
+	    ccb->csio.sense_len - ccb->csio.sense_resid,
+	    error_code, sense_key, asc, ascq, 1);
+	if (*error_code == -1)
+		return (0);
+	return (1);
+}
+
+/*
  * Extract basic sense information.  If show_errors is set, sense values
  * will be set to -1 if they are not present.
  */
@@ -5740,6 +5950,66 @@
 		      timeout);
 }
 
+void
+scsi_read_buffer(struct ccb_scsiio *csio, u_int32_t retries,
+			void (*cbfcnp)(struct cam_periph *, union ccb*),
+			uint8_t tag_action, int mode,
+			uint8_t buffer_id, u_int32_t offset,
+			uint8_t *data_ptr, uint32_t allocation_length,
+			uint8_t sense_len, uint32_t timeout)
+{
+	struct scsi_read_buffer *scsi_cmd;
+
+	scsi_cmd = (struct scsi_read_buffer *)&csio->cdb_io.cdb_bytes;
+	memset(scsi_cmd, 0, sizeof(*scsi_cmd));
+	scsi_cmd->opcode = READ_BUFFER;
+	scsi_cmd->byte2 = mode;
+	scsi_cmd->buffer_id = buffer_id;
+	scsi_ulto3b(offset, scsi_cmd->offset);
+	scsi_ulto3b(allocation_length, scsi_cmd->length);
+
+	cam_fill_csio(csio,
+		      retries,
+		      cbfcnp,
+		      /*flags*/CAM_DIR_IN,
+		      tag_action,
+		      data_ptr,
+		      allocation_length,
+		      sense_len,
+		      sizeof(*scsi_cmd),
+		      timeout);
+}
+
+void
+scsi_write_buffer(struct ccb_scsiio *csio, u_int32_t retries,
+			void (*cbfcnp)(struct cam_periph *, union ccb *),
+			uint8_t tag_action, int mode,
+			uint8_t buffer_id, u_int32_t offset,
+			uint8_t *data_ptr, uint32_t param_list_length,
+			uint8_t sense_len, uint32_t timeout)
+{
+	struct scsi_write_buffer *scsi_cmd;
+
+	scsi_cmd = (struct scsi_write_buffer *)&csio->cdb_io.cdb_bytes;
+	memset(scsi_cmd, 0, sizeof(*scsi_cmd));
+	scsi_cmd->opcode = WRITE_BUFFER;
+	scsi_cmd->byte2 = mode;
+	scsi_cmd->buffer_id = buffer_id;
+	scsi_ulto3b(offset, scsi_cmd->offset);
+	scsi_ulto3b(param_list_length, scsi_cmd->length);
+
+	cam_fill_csio(csio,
+		      retries,
+		      cbfcnp,
+		      /*flags*/param_list_length ? CAM_DIR_OUT : CAM_DIR_NONE,
+		      tag_action,
+		      data_ptr,
+		      param_list_length,
+		      sense_len,
+		      sizeof(*scsi_cmd),
+		      timeout);
+}
+
 void 
 scsi_start_stop(struct ccb_scsiio *csio, u_int32_t retries,
 		void (*cbfcnp)(struct cam_periph *, union ccb *),
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/scsi/scsi_all.h
--- a/head/sys/cam/scsi/scsi_all.h	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/scsi/scsi_all.h	Wed Jul 25 16:45:04 2012 +0300
@@ -14,7 +14,7 @@
  *
  * Ported to run under 386BSD by Julian Elischer (julian at tfs.com) Sept 1992
  *
- * $FreeBSD: head/sys/cam/scsi/scsi_all.h 230590 2012-01-26 18:09:28Z ken $
+ * $FreeBSD: head/sys/cam/scsi/scsi_all.h 237478 2012-06-23 12:32:53Z mav $
  */
 
 /*
@@ -74,9 +74,6 @@
 	SS_TUR      = 0x040000,	/* Send a Test Unit Ready command to the
 				 * device, then retry the original command.
 				 */
-	SS_REQSENSE = 0x050000,	/* Send a RequestSense command to the
-				 * device, then retry the original command.
-				 */
 	SS_MASK     = 0xff0000
 } scsi_sense_action;
 
@@ -1267,6 +1264,8 @@
 #define	SCSI_PROTO_RDMA		0x04
 #define SCSI_PROTO_iSCSI	0x05
 #define	SCSI_PROTO_SAS		0x06
+#define	SCSI_PROTO_ADT		0x07
+#define	SCSI_PROTO_ATA		0x08
 #define	SVPD_ID_PROTO_SHIFT	4
 #define	SVPD_ID_CODESET_BINARY	0x01
 #define	SVPD_ID_CODESET_ASCII	0x02
@@ -1400,6 +1399,13 @@
 	uint8_t control;
 };
 
+struct scsi_diag_page {
+	uint8_t page_code;
+	uint8_t page_specific_flags;
+	uint8_t length[2];
+	uint8_t params[0];
+};
+
 struct scsi_read_capacity
 {
 	u_int8_t opcode;
@@ -2174,12 +2180,6 @@
 char *		scsi_sense_string(struct ccb_scsiio *csio,
 				  char *str, int str_len);
 void		scsi_sense_print(struct ccb_scsiio *csio);
-int		scsi_interpret_sense(union ccb *ccb, 
-				     u_int32_t sense_flags,
-				     u_int32_t *relsim_flags, 
-				     u_int32_t *reduction,
-				     u_int32_t *timeout,
-				     scsi_sense_action error_action);
 #else /* _KERNEL */
 int		scsi_command_string(struct cam_device *device,
 				    struct ccb_scsiio *csio, struct sbuf *sb);
@@ -2191,21 +2191,8 @@
 				  char *str, int str_len);
 void		scsi_sense_print(struct cam_device *device, 
 				 struct ccb_scsiio *csio, FILE *ofile);
-int		scsi_interpret_sense(struct cam_device *device,
-				     union ccb *ccb,
-				     u_int32_t sense_flags,
-				     u_int32_t *relsim_flags, 
-				     u_int32_t *reduction,
-				     u_int32_t *timeout,
-				     scsi_sense_action error_action);
 #endif /* _KERNEL */
 
-#define	SF_RETRY_UA	0x01
-#define	SF_NO_PRINT	0x02
-#define	SF_QUIET_IR	0x04	/* Be quiet about Illegal Request reponses */
-#define	SF_PRINT_ALWAYS	0x08
-
-
 const char *	scsi_op_desc(u_int16_t opcode, 
 			     struct scsi_inquiry_data *inq_data);
 char *		scsi_cdb_string(u_int8_t *cdb_ptr, char *cdb_string,
@@ -2352,6 +2339,20 @@
 			  uint16_t param_list_length, uint8_t sense_len,
 			  uint32_t timeout);
 
+void scsi_read_buffer(struct ccb_scsiio *csio, u_int32_t retries,
+			void (*cbfcnp)(struct cam_periph *, union ccb*),
+			uint8_t tag_action, int mode,
+			uint8_t buffer_id, u_int32_t offset,
+			uint8_t *data_ptr, uint32_t allocation_length,
+			uint8_t sense_len, uint32_t timeout);
+
+void scsi_write_buffer(struct ccb_scsiio *csio, u_int32_t retries,
+			void (*cbfcnp)(struct cam_periph *, union ccb *),
+			uint8_t tag_action, int mode,
+			uint8_t buffer_id, u_int32_t offset,
+			uint8_t *data_ptr, uint32_t param_list_length,
+			uint8_t sense_len, uint32_t timeout);
+
 void scsi_read_write(struct ccb_scsiio *csio, u_int32_t retries,
 		     void (*cbfcnp)(struct cam_periph *, union ccb *),
 		     u_int8_t tag_action, int readop, u_int8_t byte2, 
@@ -2387,6 +2388,8 @@
 
 void scsi_extract_sense(struct scsi_sense_data *sense, int *error_code,
 			int *sense_key, int *asc, int *ascq);
+int scsi_extract_sense_ccb(union ccb *ccb, int *error_code, int *sense_key,
+			   int *asc, int *ascq);
 void scsi_extract_sense_len(struct scsi_sense_data *sense,
 			    u_int sense_len, int *error_code, int *sense_key,
 			    int *asc, int *ascq, int show_errors);
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/scsi/scsi_cd.c
--- a/head/sys/cam/scsi/scsi_cd.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/scsi/scsi_cd.c	Wed Jul 25 16:45:04 2012 +0300
@@ -46,7 +46,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_cd.c 229395 2012-01-03 17:04:09Z mav $");
+__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_cd.c 237689 2012-06-28 07:01:48Z imp $");
 
 #include "opt_cd.h"
 
@@ -97,15 +97,13 @@
 	CD_FLAG_NEW_DISC	= 0x0002,
 	CD_FLAG_DISC_LOCKED	= 0x0004,
 	CD_FLAG_DISC_REMOVABLE	= 0x0008,
-	CD_FLAG_TAGGED_QUEUING	= 0x0010,
 	CD_FLAG_CHANGER		= 0x0040,
 	CD_FLAG_ACTIVE		= 0x0080,
 	CD_FLAG_SCHED_ON_COMP	= 0x0100,
 	CD_FLAG_RETRY_UA	= 0x0200,
 	CD_FLAG_VALID_MEDIA	= 0x0400,
 	CD_FLAG_VALID_TOC	= 0x0800,
-	CD_FLAG_SCTX_INIT	= 0x1000,
-	CD_FLAG_OPEN		= 0x2000
+	CD_FLAG_SCTX_INIT	= 0x1000
 } cd_flags;
 
 typedef enum {
@@ -295,6 +293,9 @@
 #ifndef	CD_DEFAULT_RETRY
 #define	CD_DEFAULT_RETRY	4
 #endif
+#ifndef	CD_DEFAULT_TIMEOUT
+#define	CD_DEFAULT_TIMEOUT	30000
+#endif
 #ifndef CHANGER_MIN_BUSY_SECONDS
 #define CHANGER_MIN_BUSY_SECONDS	5
 #endif
@@ -303,6 +304,7 @@
 #endif
 
 static int cd_retry_count = CD_DEFAULT_RETRY;
+static int cd_timeout = CD_DEFAULT_TIMEOUT;
 static int changer_min_busy_seconds = CHANGER_MIN_BUSY_SECONDS;
 static int changer_max_busy_seconds = CHANGER_MAX_BUSY_SECONDS;
 
@@ -312,6 +314,9 @@
 SYSCTL_INT(_kern_cam_cd, OID_AUTO, retry_count, CTLFLAG_RW,
            &cd_retry_count, 0, "Normal I/O retry count");
 TUNABLE_INT("kern.cam.cd.retry_count", &cd_retry_count);
+SYSCTL_INT(_kern_cam_cd, OID_AUTO, timeout, CTLFLAG_RW,
+	   &cd_timeout, 0, "Timeout, in us, for read operations");
+TUNABLE_INT("kern.cam.cd.timeout", &cd_timeout);
 SYSCTL_INT(_kern_cam_cd_changer, OID_AUTO, min_busy_seconds, CTLFLAG_RW,
 	   &changer_min_busy_seconds, 0, "Minimum changer scheduling quantum");
 TUNABLE_INT("kern.cam.cd.changer.min_busy_seconds", &changer_min_busy_seconds);
@@ -359,6 +364,20 @@
 	}
 }
 
+/*
+ * Callback from GEOM, called when it has finished cleaning up its
+ * resources.
+ */
+static void
+cddiskgonecb(struct disk *dp)
+{
+	struct cam_periph *periph;
+
+	periph = (struct cam_periph *)dp->d_drv1;
+
+	cam_periph_release(periph);
+}
+
 static void
 cdoninvalidate(struct cam_periph *periph)
 {
@@ -390,7 +409,7 @@
 		camq_remove(&softc->changer->devq, softc->pinfo.index);
 
 	disk_gone(softc->disk);
-	xpt_print(periph->path, "lost device\n");
+	xpt_print(periph->path, "lost device, %d refs\n", periph->refcount);
 }
 
 static void
@@ -653,8 +672,6 @@
 	bioq_init(&softc->bio_queue);
 	if (SID_IS_REMOVABLE(&cgd->inq_data))
 		softc->flags |= CD_FLAG_DISC_REMOVABLE;
-	if ((cgd->inq_data.flags & SID_CmdQue) != 0)
-		softc->flags |= CD_FLAG_TAGGED_QUEUING;
 
 	periph->softc = softc;
 	softc->periph = periph;
@@ -729,6 +746,7 @@
 	softc->disk->d_open = cdopen;
 	softc->disk->d_close = cdclose;
 	softc->disk->d_strategy = cdstrategy;
+	softc->disk->d_gone = cddiskgonecb;
 	softc->disk->d_ioctl = cdioctl;
 	softc->disk->d_name = "cd";
 	cam_strvis(softc->disk->d_descr, cgd->inq_data.vendor,
@@ -750,6 +768,19 @@
 	softc->disk->d_hba_device = cpi.hba_device;
 	softc->disk->d_hba_subvendor = cpi.hba_subvendor;
 	softc->disk->d_hba_subdevice = cpi.hba_subdevice;
+
+	/*
+	 * Acquire a reference to the periph before we register with GEOM.
+	 * We'll release this reference once GEOM calls us back (via
+	 * dadiskgonecb()) telling us that our provider has been freed.
+	 */
+	if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
+		xpt_print(periph->path, "%s: lost periph during "
+			  "registration!\n", __func__);
+		cam_periph_lock(periph);
+		return (CAM_REQ_CMP_ERR);
+	}
+
 	disk_create(softc->disk, DISK_VERSION);
 	cam_periph_lock(periph);
 
@@ -1003,17 +1034,20 @@
 	cam_periph_lock(periph);
 
 	if (softc->flags & CD_FLAG_INVALID) {
+		cam_periph_release_locked(periph);
 		cam_periph_unlock(periph);
-		cam_periph_release(periph);
 		return(ENXIO);
 	}
 
 	if ((error = cam_periph_hold(periph, PRIBIO | PCATCH)) != 0) {
+		cam_periph_release_locked(periph);
 		cam_periph_unlock(periph);
-		cam_periph_release(periph);
 		return (error);
 	}
 
+	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH,
+	    ("cdopen\n"));
+
 	/*
 	 * Check for media, and set the appropriate flags.  We don't bail
 	 * if we don't have media, but then we don't allow anything but the
@@ -1024,14 +1058,7 @@
 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdopen\n"));
 	cam_periph_unhold(periph);
 
-	/* Closes aren't symmetrical with opens, so fix up the refcounting. */
-	if ((softc->flags & CD_FLAG_OPEN) == 0) {
-		softc->flags |= CD_FLAG_OPEN;
-		cam_periph_unlock(periph);
-	} else {
-		cam_periph_unlock(periph);
-		cam_periph_release(periph);
-	}
+	cam_periph_unlock(periph);
 
 	return (0);
 }
@@ -1049,7 +1076,14 @@
 	softc = (struct cd_softc *)periph->softc;
 
 	cam_periph_lock(periph);
-	cam_periph_hold(periph, PRIBIO);
+	if (cam_periph_hold(periph, PRIBIO) != 0) {
+		cam_periph_unlock(periph);
+		cam_periph_release(periph);
+		return (0);
+	}
+
+	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH,
+	    ("cdclose\n"));
 
 	if ((softc->flags & CD_FLAG_DISC_REMOVABLE) != 0)
 		cdprevent(periph, PR_ALLOW);
@@ -1063,11 +1097,11 @@
 	/*
 	 * We'll check the media and toc again at the next open().
 	 */
-	softc->flags &= ~(CD_FLAG_VALID_MEDIA|CD_FLAG_VALID_TOC|CD_FLAG_OPEN);
+	softc->flags &= ~(CD_FLAG_VALID_MEDIA|CD_FLAG_VALID_TOC);
 
 	cam_periph_unhold(periph);
+	cam_periph_release_locked(periph);
 	cam_periph_unlock(periph);
-	cam_periph_release(periph);
 
 	return (0);
 }
@@ -1395,7 +1429,8 @@
 	}
 
 	cam_periph_lock(periph);
-	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdstrategy\n"));
+	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
+	    ("cdstrategy(%p)\n", bp));
 
 	softc = (struct cd_softc *)periph->softc;
 
@@ -1481,8 +1516,9 @@
 					bp->bio_bcount / softc->params.blksize,
 					/* data_ptr */ bp->bio_data,
 					/* dxfer_len */ bp->bio_bcount,
-					/* sense_len */ SSD_FULL_SIZE,
-					/* timeout */ 30000);
+					/* sense_len */ cd_retry_count ?
+					  SSD_FULL_SIZE : SF_NO_PRINT,
+					/* timeout */ cd_timeout);
 			/* Use READ CD command for audio tracks. */
 			if (softc->params.blksize == 2352) {
 				start_ccb->csio.cdb_io.cdb_bytes[0] = READ_CD;
@@ -1668,7 +1704,6 @@
 				return;
 			} else if (error != 0) {
 
-				struct scsi_sense_data *sense;
 				int asc, ascq;
 				int sense_key, error_code;
 				int have_sense;
@@ -1691,20 +1726,12 @@
 				cgd.ccb_h.func_code = XPT_GDEV_TYPE;
 				xpt_action((union ccb *)&cgd);
 
-				if (((csio->ccb_h.flags & CAM_SENSE_PHYS) != 0)
-				 || ((csio->ccb_h.flags & CAM_SENSE_PTR) != 0)
-				 || ((status & CAM_AUTOSNS_VALID) == 0))
+				if (scsi_extract_sense_ccb(done_ccb,
+				    &error_code, &sense_key, &asc, &ascq))
+					have_sense = TRUE;
+				else
 					have_sense = FALSE;
-				else
-					have_sense = TRUE;
-
-				if (have_sense) {
-					sense = &csio->sense_data;
-					scsi_extract_sense_len(sense,
-					    csio->sense_len - csio->sense_resid,
-					    &error_code, &sense_key, &asc,
-					    &ascq, /*show_errors*/ 1);
-				}
+
 				/*
 				 * Attach to anything that claims to be a
 				 * CDROM or WORM device, as long as it
@@ -1861,12 +1888,11 @@
 		return(ENXIO);	
 
 	cam_periph_lock(periph);
-	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdioctl\n"));
 
 	softc = (struct cd_softc *)periph->softc;
 
-	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 
-		  ("trying to do ioctl %#lx\n", cmd));
+	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
+	    ("cdioctl(%#lx)\n", cmd));
 
 	if ((error = cam_periph_hold(periph, PRIBIO | PCATCH)) != 0) {
 		cam_periph_unlock(periph);
@@ -3131,7 +3157,7 @@
 {
 	struct cd_softc *softc;
 	struct cam_periph *periph;
-	int error;
+	int error, error_code, sense_key, asc, ascq;
 
 	periph = xpt_path_periph(ccb->ccb_h.path);
 	softc = (struct cd_softc *)periph->softc;
@@ -3145,19 +3171,10 @@
 	 */
 	if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INVALID) {
 		error = cd6byteworkaround(ccb);
-	} else if (((ccb->ccb_h.status & CAM_STATUS_MASK) ==
-		     CAM_SCSI_STATUS_ERROR)
-	 && (ccb->ccb_h.status & CAM_AUTOSNS_VALID)
-	 && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND)
-	 && ((ccb->ccb_h.flags & CAM_SENSE_PHYS) == 0)
-	 && ((ccb->ccb_h.flags & CAM_SENSE_PTR) == 0)) {
-		int sense_key, error_code, asc, ascq;
-
- 		scsi_extract_sense_len(&ccb->csio.sense_data,
-		    ccb->csio.sense_len - ccb->csio.sense_resid, &error_code,
-		    &sense_key, &asc, &ascq, /*show_errors*/ 1);
+	} else if (scsi_extract_sense_ccb(ccb,
+	    &error_code, &sense_key, &asc, &ascq)) {
 		if (sense_key == SSD_KEY_ILLEGAL_REQUEST)
- 			error = cd6byteworkaround(ccb);
+			error = cd6byteworkaround(ccb);
 	}
 
 	if (error == ERESTART)
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/scsi/scsi_ch.c
--- a/head/sys/cam/scsi/scsi_ch.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/scsi/scsi_ch.c	Wed Jul 25 16:45:04 2012 +0300
@@ -68,7 +68,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_ch.c 227293 2011-11-07 06:44:47Z ed $");
+__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_ch.c 238200 2012-07-07 17:17:43Z eadler $");
 
 #include <sys/param.h>
 #include <sys/queue.h>
@@ -107,8 +107,7 @@
 static const u_int32_t	CH_TIMEOUT_INITIALIZE_ELEMENT_STATUS = 500000;
 
 typedef enum {
-	CH_FLAG_INVALID		= 0x001,
-	CH_FLAG_OPEN		= 0x002
+	CH_FLAG_INVALID		= 0x001
 } ch_flags;
 
 typedef enum {
@@ -211,7 +210,7 @@
 
 static struct cdevsw ch_cdevsw = {
 	.d_version =	D_VERSION,
-	.d_flags =	0,
+	.d_flags =	D_TRACKCLOSE,
 	.d_open =	chopen,
 	.d_close =	chclose,
 	.d_ioctl =	chioctl,
@@ -404,16 +403,11 @@
 	cam_periph_lock(periph);
 	
 	if (softc->flags & CH_FLAG_INVALID) {
+		cam_periph_release_locked(periph);
 		cam_periph_unlock(periph);
-		cam_periph_release(periph);
 		return(ENXIO);
 	}
 
-	if ((softc->flags & CH_FLAG_OPEN) == 0)
-		softc->flags |= CH_FLAG_OPEN;
-	else
-		cam_periph_release(periph);
-
 	if ((error = cam_periph_hold(periph, PRIBIO | PCATCH)) != 0) {
 		cam_periph_unlock(periph);
 		cam_periph_release(periph);
@@ -424,9 +418,8 @@
 	 * Load information about this changer device into the softc.
 	 */
 	if ((error = chgetparams(periph)) != 0) {
-		softc->flags &= ~CH_FLAG_OPEN;
+		cam_periph_release_locked(periph);
 		cam_periph_unlock(periph);
-		cam_periph_release(periph);
 		return(error);
 	}
 
@@ -440,22 +433,11 @@
 chclose(struct cdev *dev, int flag, int fmt, struct thread *td)
 {
 	struct	cam_periph *periph;
-	struct	ch_softc *softc;
-	int	error;
-
-	error = 0;
 
 	periph = (struct cam_periph *)dev->si_drv1;
 	if (periph == NULL)
 		return(ENXIO);
 
-	softc = (struct ch_softc *)periph->softc;
-
-	cam_periph_lock(periph);
-
-	softc->flags &= ~CH_FLAG_OPEN;
-
-	cam_periph_unlock(periph);
 	cam_periph_release(periph);
 
 	return(0);
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/scsi/scsi_da.c
--- a/head/sys/cam/scsi/scsi_da.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/scsi/scsi_da.c	Wed Jul 25 16:45:04 2012 +0300
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_da.c 234374 2012-04-17 10:44:28Z trasz $");
+__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_da.c 238437 2012-07-14 02:59:11Z mjacob $");
 
 #include <sys/param.h>
 
@@ -77,7 +77,6 @@
 	DA_FLAG_NEW_PACK	= 0x002,
 	DA_FLAG_PACK_LOCKED	= 0x004,
 	DA_FLAG_PACK_REMOVABLE	= 0x008,
-	DA_FLAG_TAGGED_QUEUING	= 0x010,
 	DA_FLAG_NEED_OTAG	= 0x020,
 	DA_FLAG_WENT_IDLE	= 0x040,
 	DA_FLAG_RETRY_UA	= 0x080,
@@ -811,6 +810,27 @@
 		{ T_DIRECT, SIP_MEDIA_FIXED, "WDC WD??", "???PVT*", "*" },
 		/*quirks*/DA_Q_4K
 	},
+	{
+		/*
+		 * Olympus FE-210 camera
+		 */
+		{T_DIRECT, SIP_MEDIA_REMOVABLE, "OLYMPUS", "FE210*",
+		"*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
+	},
+	{
+		/*
+		 * LG UP3S MP3 player
+		 */
+		{T_DIRECT, SIP_MEDIA_REMOVABLE, "LG", "UP3S",
+		"*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
+	},
+	{
+		/*
+		 * Laser MP3-2GA13 MP3 player
+		 */
+		{T_DIRECT, SIP_MEDIA_REMOVABLE, "USB 2.0", "(HS) Flash Disk",
+		"*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE
+	},
 };
 
 static	disk_strategy_t	dastrategy;
@@ -863,9 +883,9 @@
 SYSCTL_INT(_kern_cam_da, OID_AUTO, default_timeout, CTLFLAG_RW,
            &da_default_timeout, 0, "Normal I/O timeout (in seconds)");
 TUNABLE_INT("kern.cam.da.default_timeout", &da_default_timeout);
-SYSCTL_INT(_kern_cam_da, OID_AUTO, da_send_ordered, CTLFLAG_RW,
+SYSCTL_INT(_kern_cam_da, OID_AUTO, send_ordered, CTLFLAG_RW,
            &da_send_ordered, 0, "Send Ordered Tags");
-TUNABLE_INT("kern.cam.da.da_send_ordered", &da_send_ordered);
+TUNABLE_INT("kern.cam.da.send_ordered", &da_send_ordered);
 
 /*
  * DA_ORDEREDTAG_INTERVAL determines how often, relative
@@ -921,9 +941,8 @@
 	softc = (struct da_softc *)periph->softc;
 	softc->flags |= DA_FLAG_OPEN;
 
-	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
-	    ("daopen: disk=%s%d (unit %d)\n", dp->d_name, dp->d_unit,
-	     unit));
+	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH,
+	    ("daopen\n"));
 
 	if ((softc->flags & DA_FLAG_PACK_INVALID) != 0) {
 		/* Invalidate our pack information. */
@@ -963,14 +982,13 @@
 {
 	struct	cam_periph *periph;
 	struct	da_softc *softc;
-	int error;
 
 	periph = (struct cam_periph *)dp->d_drv1;
 	if (periph == NULL)
 		return (0);	
 
 	cam_periph_lock(periph);
-	if ((error = cam_periph_hold(periph, PRIBIO)) != 0) {
+	if (cam_periph_hold(periph, PRIBIO) != 0) {
 		cam_periph_unlock(periph);
 		cam_periph_release(periph);
 		return (0);
@@ -978,6 +996,9 @@
 
 	softc = (struct da_softc *)periph->softc;
 
+	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH,
+	    ("daclose\n"));
+
 	if ((softc->quirks & DA_Q_NO_SYNC_CACHE) == 0
 	 && (softc->flags & DA_FLAG_PACK_INVALID) == 0) {
 		union	ccb *ccb;
@@ -993,30 +1014,9 @@
 				       SSD_FULL_SIZE,
 				       5 * 60 * 1000);
 
-		cam_periph_runccb(ccb, /*error_routine*/NULL, /*cam_flags*/0,
-				  /*sense_flags*/SF_RETRY_UA,
+		cam_periph_runccb(ccb, daerror, /*cam_flags*/0,
+				  /*sense_flags*/SF_RETRY_UA | SF_QUIET_IR,
 				  softc->disk->d_devstat);
-
-		if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
-			if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
-			     CAM_SCSI_STATUS_ERROR) {
-				int asc, ascq;
-				int sense_key, error_code;
-
-				scsi_extract_sense_len(&ccb->csio.sense_data,
-				    ccb->csio.sense_len - ccb->csio.sense_resid,
-				    &error_code, &sense_key, &asc, &ascq,
-				    /*show_errors*/ 1);
-				if (sense_key != SSD_KEY_ILLEGAL_REQUEST)
-					scsi_sense_print(&ccb->csio);
-			} else {
-				xpt_print(periph->path, "Synchronize cache "
-				    "failed, status == 0x%x, scsi status == "
-				    "0x%x\n", ccb->csio.ccb_h.status,
-				    ccb->csio.scsi_status);
-			}
-		}
-
 		xpt_release_ccb(ccb);
 
 	}
@@ -1087,7 +1087,9 @@
 		biofinish(bp, NULL, ENXIO);
 		return;
 	}
-	
+
+	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("dastrategy(%p)\n", bp));
+
 	/*
 	 * Place it in the queue of disk activities for this disk
 	 */
@@ -1116,6 +1118,7 @@
 	u_int	    secsize;
 	struct	    ccb_scsiio csio;
 	struct	    disk *dp;
+	int	    error = 0;
 
 	dp = arg;
 	periph = dp->d_drv1;
@@ -1134,7 +1137,7 @@
 		xpt_setup_ccb(&csio.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
 		csio.ccb_h.ccb_state = DA_CCB_DUMP;
 		scsi_read_write(&csio,
-				/*retries*/1,
+				/*retries*/0,
 				dadone,
 				MSG_ORDERED_Q_TAG,
 				/*read*/FALSE,
@@ -1147,19 +1150,16 @@
 				/*sense_len*/SSD_FULL_SIZE,
 				da_default_timeout * 1000);
 		xpt_polled_action((union ccb *)&csio);
+
+		error = cam_periph_error((union ccb *)&csio,
+		    0, SF_NO_RECOVERY | SF_NO_RETRY, NULL);
+		if ((csio.ccb_h.status & CAM_DEV_QFRZN) != 0)
+			cam_release_devq(csio.ccb_h.path, /*relsim_flags*/0,
+			    /*reduction*/0, /*timeout*/0, /*getcount_only*/0);
+		if (error != 0)
+			printf("Aborting dump due to I/O error.\n");
 		cam_periph_unlock(periph);
-
-		if ((csio.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
-			printf("Aborting dump due to I/O error.\n");
-			if ((csio.ccb_h.status & CAM_STATUS_MASK) ==
-			     CAM_SCSI_STATUS_ERROR)
-				scsi_sense_print(&csio);
-			else
-				printf("status == 0x%x, scsi status == 0x%x\n",
-				       csio.ccb_h.status, csio.scsi_status);
-			return(EIO);
-		}
-		return(0);
+		return (error);
 	}
 		
 	/*
@@ -1170,7 +1170,7 @@
 		xpt_setup_ccb(&csio.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
 		csio.ccb_h.ccb_state = DA_CCB_DUMP;
 		scsi_synchronize_cache(&csio,
-				       /*retries*/1,
+				       /*retries*/0,
 				       /*cbfcnp*/dadone,
 				       MSG_SIMPLE_Q_TAG,
 				       /*begin_lba*/0,/* Cover the whole disk */
@@ -1179,28 +1179,16 @@
 				       5 * 60 * 1000);
 		xpt_polled_action((union ccb *)&csio);
 
-		if ((csio.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
-			if ((csio.ccb_h.status & CAM_STATUS_MASK) ==
-			     CAM_SCSI_STATUS_ERROR) {
-				int asc, ascq;
-				int sense_key, error_code;
-
-				scsi_extract_sense_len(&csio.sense_data,
-				    csio.sense_len - csio.sense_resid,
-				    &error_code, &sense_key, &asc, &ascq,
-				    /*show_errors*/ 1);
-				if (sense_key != SSD_KEY_ILLEGAL_REQUEST)
-					scsi_sense_print(&csio);
-			} else {
-				xpt_print(periph->path, "Synchronize cache "
-				    "failed, status == 0x%x, scsi status == "
-				    "0x%x\n", csio.ccb_h.status,
-				    csio.scsi_status);
-			}
-		}
+		error = cam_periph_error((union ccb *)&csio,
+		    0, SF_NO_RECOVERY | SF_NO_RETRY | SF_QUIET_IR, NULL);
+		if ((csio.ccb_h.status & CAM_DEV_QFRZN) != 0)
+			cam_release_devq(csio.ccb_h.path, /*relsim_flags*/0,
+			    /*reduction*/0, /*timeout*/0, /*getcount_only*/0);
+		if (error != 0)
+			xpt_print(periph->path, "Synchronize cache failed\n");
 	}
 	cam_periph_unlock(periph);
-	return (0);
+	return (error);
 }
 
 static int
@@ -1245,6 +1233,20 @@
 	}
 }
 
+/*
+ * Callback from GEOM, called when it has finished cleaning up its
+ * resources.
+ */
+static void
+dadiskgonecb(struct disk *dp)
+{
+	struct cam_periph *periph;
+
+	periph = (struct cam_periph *)dp->d_drv1;
+
+	cam_periph_release(periph);
+}
+
 static void
 daoninvalidate(struct cam_periph *periph)
 {
@@ -1267,7 +1269,12 @@
 	bioq_flush(&softc->bio_queue, NULL, ENXIO);
 	bioq_flush(&softc->delete_queue, NULL, ENXIO);
 
+	/*
+	 * Tell GEOM that we've gone away, we'll get a callback when it is
+	 * done cleaning up its resources.
+	 */
 	disk_gone(softc->disk);
+
 	xpt_print(periph->path, "lost device - %d outstanding, %d refs\n",
 		  softc->outstanding_cmds, periph->refcount);
 }
@@ -1550,8 +1557,6 @@
 	bioq_init(&softc->delete_run_queue);
 	if (SID_IS_REMOVABLE(&cgd->inq_data))
 		softc->flags |= DA_FLAG_PACK_REMOVABLE;
-	if ((cgd->inq_data.flags & SID_CmdQue) != 0)
-		softc->flags |= DA_FLAG_TAGGED_QUEUING;
 	softc->unmap_max_ranges = UNMAP_MAX_RANGES;
 	softc->unmap_max_lba = 1024*1024*2;
 
@@ -1647,6 +1652,7 @@
 	softc->disk->d_strategy = dastrategy;
 	softc->disk->d_dump = dadump;
 	softc->disk->d_getattr = dagetattr;
+	softc->disk->d_gone = dadiskgonecb;
 	softc->disk->d_name = "da";
 	softc->disk->d_drv1 = periph;
 	if (cpi.maxio == 0)
@@ -1669,6 +1675,19 @@
 	softc->disk->d_hba_device = cpi.hba_device;
 	softc->disk->d_hba_subvendor = cpi.hba_subvendor;
 	softc->disk->d_hba_subdevice = cpi.hba_subdevice;
+
+	/*
+	 * Acquire a reference to the periph before we register with GEOM.
+	 * We'll release this reference once GEOM calls us back (via
+	 * dadiskgonecb()) telling us that our provider has been freed.
+	 */
+	if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
+		xpt_print(periph->path, "%s: lost periph during "
+			  "registration!\n", __func__);
+		mtx_lock(periph->sim->mtx);
+		return (CAM_REQ_CMP_ERR);
+	}
+
 	disk_create(softc->disk, DISK_VERSION);
 	mtx_lock(periph->sim->mtx);
 
@@ -1703,6 +1722,8 @@
 
 	softc = (struct da_softc *)periph->softc;
 
+	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("dastart\n"));
+
 	switch (softc->state) {
 	case DA_STATE_NORMAL:
 	{
@@ -1711,7 +1732,7 @@
 
 		/* Execute immediate CCB if waiting. */
 		if (periph->immediate_priority <= periph->pinfo.priority) {
-			CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE,
+			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
 					("queuing for immediate ccb\n"));
 			start_ccb->ccb_h.ccb_state = DA_CCB_WAITING;
 			SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
@@ -2043,6 +2064,9 @@
 
 	softc = (struct da_softc *)periph->softc;
 	priority = done_ccb->ccb_h.pinfo.priority;
+
+	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("dadone\n"));
+
 	csio = &done_ccb->csio;
 	switch (csio->ccb_h.ccb_state & DA_CCB_TYPE_MASK) {
 	case DA_CCB_BUFFER_IO:
@@ -2263,7 +2287,6 @@
 				 */
 				return;
 			} else if (error != 0) {
-				struct scsi_sense_data *sense;
 				int asc, ascq;
 				int sense_key, error_code;
 				int have_sense;
@@ -2286,20 +2309,12 @@
 				cgd.ccb_h.func_code = XPT_GDEV_TYPE;
 				xpt_action((union ccb *)&cgd);
 
-				if (((csio->ccb_h.flags & CAM_SENSE_PHYS) != 0)
-				 || ((csio->ccb_h.flags & CAM_SENSE_PTR) != 0)
-				 || ((status & CAM_AUTOSNS_VALID) == 0))
+				if (scsi_extract_sense_ccb(done_ccb,
+				    &error_code, &sense_key, &asc, &ascq))
+					have_sense = TRUE;
+				else
 					have_sense = FALSE;
-				else
-					have_sense = TRUE;
 
-				if (have_sense) {
-					sense = &csio->sense_data;
-					scsi_extract_sense_len(sense,
-					    csio->sense_len - csio->sense_resid,
-					    &error_code, &sense_key, &asc,
-					    &ascq, /*show_errors*/ 1);
-				}
 				/*
 				 * If we tried READ CAPACITY(16) and failed,
 				 * fallback to READ CAPACITY(10).
@@ -2437,7 +2452,7 @@
 {
 	struct da_softc	  *softc;
 	struct cam_periph *periph;
-	int error;
+	int error, error_code, sense_key, asc, ascq;
 
 	periph = xpt_path_periph(ccb->ccb_h.path);
 	softc = (struct da_softc *)periph->softc;
@@ -2449,16 +2464,8 @@
 	error = 0;
 	if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INVALID) {
 		error = cmd6workaround(ccb);
-	} else if (((ccb->ccb_h.status & CAM_STATUS_MASK) ==
-		   CAM_SCSI_STATUS_ERROR)
-	 && (ccb->ccb_h.status & CAM_AUTOSNS_VALID)
-	 && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND)
-	 && ((ccb->ccb_h.flags & CAM_SENSE_PHYS) == 0)
-	 && ((ccb->ccb_h.flags & CAM_SENSE_PTR) == 0)) {
-		int sense_key, error_code, asc, ascq;
-
- 		scsi_extract_sense(&ccb->csio.sense_data,
-				   &error_code, &sense_key, &asc, &ascq);
+	} else if (scsi_extract_sense_ccb(ccb,
+	    &error_code, &sense_key, &asc, &ascq)) {
 		if (sense_key == SSD_KEY_ILLEGAL_REQUEST)
  			error = cmd6workaround(ccb);
 		/*
@@ -2511,8 +2518,8 @@
 		     SSD_FULL_SIZE,
 		     5000);
 
-	error = cam_periph_runccb(ccb, /*error_routine*/NULL, CAM_RETRY_SELTO,
-				  SF_RETRY_UA, softc->disk->d_devstat);
+	error = cam_periph_runccb(ccb, daerror, CAM_RETRY_SELTO,
+	    SF_RETRY_UA | SF_QUIET_IR, softc->disk->d_devstat);
 
 	if (error == 0) {
 		if (action == PR_ALLOW)
@@ -2637,6 +2644,11 @@
 		softc->disk->d_flags |= DISKFLAG_CANDELETE;
 	else
 		softc->disk->d_flags &= ~DISKFLAG_CANDELETE;
+
+/* Currently as of 6/13/2012, panics if DIAGNOSTIC is set */
+#ifndef	DIAGNOSTIC
+	disk_resize(softc->disk);
+#endif
 }
 
 static void
@@ -2669,6 +2681,7 @@
 {
 	struct cam_periph *periph;
 	struct da_softc *softc;
+	int error;
 
 	TAILQ_FOREACH(periph, &dadriver.units, unit_links) {
 		union ccb ccb;
@@ -2690,7 +2703,7 @@
 
 		ccb.ccb_h.ccb_state = DA_CCB_DUMP;
 		scsi_synchronize_cache(&ccb.csio,
-				       /*retries*/1,
+				       /*retries*/0,
 				       /*cbfcnp*/dadone,
 				       MSG_SIMPLE_Q_TAG,
 				       /*begin_lba*/0, /* whole disk */
@@ -2700,32 +2713,13 @@
 
 		xpt_polled_action(&ccb);
 
-		if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
-			if (((ccb.ccb_h.status & CAM_STATUS_MASK) ==
-			     CAM_SCSI_STATUS_ERROR)
-			 && (ccb.csio.scsi_status == SCSI_STATUS_CHECK_COND)){
-				int error_code, sense_key, asc, ascq;
-
-				scsi_extract_sense(&ccb.csio.sense_data,
-						   &error_code, &sense_key,
-						   &asc, &ascq);
-
-				if (sense_key != SSD_KEY_ILLEGAL_REQUEST)
-					scsi_sense_print(&ccb.csio);
-			} else {
-				xpt_print(periph->path, "Synchronize "
-				    "cache failed, status == 0x%x, scsi status "
-				    "== 0x%x\n", ccb.ccb_h.status,
-				    ccb.csio.scsi_status);
-			}
-		}
-
+		error = cam_periph_error(&ccb,
+		    0, SF_NO_RECOVERY | SF_NO_RETRY | SF_QUIET_IR, NULL);
 		if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0)
-			cam_release_devq(ccb.ccb_h.path,
-					 /*relsim_flags*/0,
-					 /*reduction*/0,
-					 /*timeout*/0,
-					 /*getcount_only*/0);
+			cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0,
+			    /*reduction*/0, /*timeout*/0, /*getcount_only*/0);
+		if (error != 0)
+			xpt_print(periph->path, "Synchronize cache failed\n");
 		cam_periph_unlock(periph);
 	}
 }
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/scsi/scsi_da.h
--- a/head/sys/cam/scsi/scsi_da.h	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/scsi/scsi_da.h	Wed Jul 25 16:45:04 2012 +0300
@@ -46,7 +46,7 @@
  *
  * Ported to run under 386BSD by Julian Elischer (julian at tfs.com) Sept 1992
  *
- * $FreeBSD: head/sys/cam/scsi/scsi_da.h 229997 2012-01-12 00:34:33Z ken $
+ * $FreeBSD: head/sys/cam/scsi/scsi_da.h 237452 2012-06-22 18:57:06Z ken $
  */
 
 #ifndef	_SCSI_SCSI_DA_H
@@ -111,6 +111,7 @@
 	u_int8_t reserved[4];
 
 	u_int8_t alloc_length[2];
+#define	SRDD10_MAX_LENGTH		0xffff
 
 	u_int8_t control;
 };
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/scsi/scsi_enc.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/cam/scsi/scsi_enc.c	Wed Jul 25 16:45:04 2012 +0300
@@ -0,0 +1,1023 @@
+/*-
+ * Copyright (c) 2000 Matthew Jacob
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_enc.c 237328 2012-06-20 17:08:00Z ken $");
+
+#include <sys/param.h>
+
+#include <sys/conf.h>
+#include <sys/errno.h>
+#include <sys/fcntl.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/sx.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+
+#include <machine/stdarg.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_debug.h>
+#include <cam/cam_periph.h>
+#include <cam/cam_xpt_periph.h>
+
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_message.h>
+#include <cam/scsi/scsi_enc.h>
+#include <cam/scsi/scsi_enc_internal.h>
+
+#include <opt_enc.h>
+
+MALLOC_DEFINE(M_SCSIENC, "SCSI ENC", "SCSI ENC buffers");
+
+/* Enclosure type independent driver */
+
+#define	SEN_ID		"UNISYS           SUN_SEN"
+#define	SEN_ID_LEN	24
+
+static	d_open_t	enc_open;
+static	d_close_t	enc_close;
+static	d_ioctl_t	enc_ioctl;
+static	periph_init_t	enc_init;
+static  periph_ctor_t	enc_ctor;
+static	periph_oninv_t	enc_oninvalidate;
+static  periph_dtor_t   enc_dtor;
+static  periph_start_t  enc_start;
+
+static void enc_async(void *, uint32_t, struct cam_path *, void *);
+static enctyp enc_type(struct ccb_getdev *);
+
+SYSCTL_NODE(_kern_cam, OID_AUTO, enc, CTLFLAG_RD, 0,
+            "CAM Enclosure Services driver");
+
+static struct periph_driver encdriver = {
+	enc_init, "ses",
+	TAILQ_HEAD_INITIALIZER(encdriver.units), /* generation */ 0
+};
+
+PERIPHDRIVER_DECLARE(enc, encdriver);
+
+static struct cdevsw enc_cdevsw = {
+	.d_version =	D_VERSION,
+	.d_open =	enc_open,
+	.d_close =	enc_close,
+	.d_ioctl =	enc_ioctl,
+	.d_name =	"ses",
+	.d_flags =	D_TRACKCLOSE,
+};
+
+static void
+enc_init(void)
+{
+	cam_status status;
+
+	/*
+	 * Install a global async callback.  This callback will
+	 * receive async callbacks like "new device found".
+	 */
+	status = xpt_register_async(AC_FOUND_DEVICE, enc_async, NULL, NULL);
+
+	if (status != CAM_REQ_CMP) {
+		printf("enc: Failed to attach master async callback "
+		       "due to status 0x%x!\n", status);
+	}
+}
+
+static void
+enc_devgonecb(void *arg)
+{
+	struct cam_periph *periph;
+
+	periph = (struct cam_periph *)arg;
+
+	cam_periph_release(periph);
+}
+
+static void
+enc_oninvalidate(struct cam_periph *periph)
+{
+	struct enc_softc *enc;
+
+	enc = periph->softc;
+
+	enc->enc_flags |= ENC_FLAG_INVALID;
+
+	/* If the sub-driver has an invalidate routine, call it */
+	if (enc->enc_vec.softc_invalidate != NULL)
+		enc->enc_vec.softc_invalidate(enc);
+
+	/*
+	 * Unregister any async callbacks.
+	 */
+	xpt_register_async(0, enc_async, periph, periph->path);
+
+	/*
+	 * Shutdown our daemon.
+	 */
+	enc->enc_flags |= ENC_FLAG_SHUTDOWN;
+	if (enc->enc_daemon != NULL) {
+		/* Signal the ses daemon to terminate. */
+		wakeup(enc->enc_daemon);
+	}
+	callout_drain(&enc->status_updater);
+
+	destroy_dev_sched_cb(enc->enc_dev, enc_devgonecb, periph);
+
+	xpt_print(periph->path, "lost device\n");
+}
+
+static void
+enc_dtor(struct cam_periph *periph)
+{
+	struct enc_softc *enc;
+
+	enc = periph->softc;
+
+	xpt_print(periph->path, "removing device entry\n");
+
+
+	/* If the sub-driver has a cleanup routine, call it */
+	if (enc->enc_vec.softc_cleanup != NULL)
+		enc->enc_vec.softc_cleanup(enc);
+
+	if (enc->enc_boot_hold_ch.ich_func != NULL) {
+		config_intrhook_disestablish(&enc->enc_boot_hold_ch);
+		enc->enc_boot_hold_ch.ich_func = NULL;
+	}
+
+	ENC_FREE(enc);
+}
+
+static void
+enc_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
+{
+	struct cam_periph *periph;
+
+	periph = (struct cam_periph *)callback_arg;
+
+	switch(code) {
+	case AC_FOUND_DEVICE:
+	{
+		struct ccb_getdev *cgd;
+		cam_status status;
+		path_id_t path_id;
+
+		cgd = (struct ccb_getdev *)arg;
+		if (arg == NULL) {
+			break;
+		}
+
+		if (enc_type(cgd) == ENC_NONE) {
+			/*
+			 * Schedule announcement of the ENC bindings for
+			 * this device if it is managed by a SEP.
+			 */
+			path_id = xpt_path_path_id(path);
+			xpt_lock_buses();
+			TAILQ_FOREACH(periph, &encdriver.units, unit_links) {
+				struct enc_softc *softc;
+
+				softc = (struct enc_softc *)periph->softc;
+				if (xpt_path_path_id(periph->path) != path_id
+				 || softc == NULL
+				 || (softc->enc_flags & ENC_FLAG_INITIALIZED)
+				  == 0
+				 || softc->enc_vec.device_found == NULL)
+					continue;
+
+				softc->enc_vec.device_found(softc);
+			}
+			xpt_unlock_buses();
+			return;
+		}
+
+		status = cam_periph_alloc(enc_ctor, enc_oninvalidate,
+		    enc_dtor, enc_start, "ses", CAM_PERIPH_BIO,
+		    cgd->ccb_h.path, enc_async, AC_FOUND_DEVICE, cgd);
+
+		if (status != CAM_REQ_CMP && status != CAM_REQ_INPROG) {
+			printf("enc_async: Unable to probe new device due to "
+			    "status 0x%x\n", status);
+		}
+		break;
+	}
+	default:
+		cam_periph_async(periph, code, path, arg);
+		break;
+	}
+}
+
+static int
+enc_open(struct cdev *dev, int flags, int fmt, struct thread *td)
+{
+	struct cam_periph *periph;
+	struct enc_softc *softc;
+	int error = 0;
+
+	periph = (struct cam_periph *)dev->si_drv1;
+	if (periph == NULL) {
+		return (ENXIO);
+	}
+
+	if (cam_periph_acquire(periph) != CAM_REQ_CMP)
+		return (ENXIO);
+
+	cam_periph_lock(periph);
+
+	softc = (struct enc_softc *)periph->softc;
+
+	if ((softc->enc_flags & ENC_FLAG_INITIALIZED) == 0) {
+		error = ENXIO;
+		goto out;
+	}
+	if (softc->enc_flags & ENC_FLAG_INVALID) {
+		error = ENXIO;
+		goto out;
+	}
+out:
+	if (error != 0)
+		cam_periph_release_locked(periph);
+
+	cam_periph_unlock(periph);
+
+	return (error);
+}
+
+static int
+enc_close(struct cdev *dev, int flag, int fmt, struct thread *td)
+{
+	struct cam_periph *periph;
+
+	periph = (struct cam_periph *)dev->si_drv1;
+	if (periph == NULL)
+		return (ENXIO);
+
+	cam_periph_release(periph);
+
+	return (0);
+}
+
+static void
+enc_start(struct cam_periph *p, union ccb *sccb)
+{
+	struct enc_softc *enc;
+
+	enc = p->softc;
+	ENC_DLOG(enc, "%s enter imm=%d prio=%d\n",
+	    __func__, p->immediate_priority, p->pinfo.priority);
+	if (p->immediate_priority <= p->pinfo.priority) {
+		SLIST_INSERT_HEAD(&p->ccb_list, &sccb->ccb_h, periph_links.sle);
+		p->immediate_priority = CAM_PRIORITY_NONE;
+		wakeup(&p->ccb_list);
+	} else
+		xpt_release_ccb(sccb);
+	ENC_DLOG(enc, "%s exit\n", __func__);
+}
+
+void
+enc_done(struct cam_periph *periph, union ccb *dccb)
+{
+	wakeup(&dccb->ccb_h.cbfcnp);
+}
+
+int
+enc_error(union ccb *ccb, uint32_t cflags, uint32_t sflags)
+{
+	struct enc_softc *softc;
+	struct cam_periph *periph;
+
+	periph = xpt_path_periph(ccb->ccb_h.path);
+	softc = (struct enc_softc *)periph->softc;
+
+	return (cam_periph_error(ccb, cflags, sflags, &softc->saved_ccb));
+}
+
+static int
+enc_ioctl(struct cdev *dev, u_long cmd, caddr_t arg_addr, int flag,
+	 struct thread *td)
+{
+	struct cam_periph *periph;
+	encioc_enc_status_t tmp;
+	encioc_string_t sstr;
+	encioc_elm_status_t elms;
+	encioc_elm_desc_t elmd;
+	encioc_elm_devnames_t elmdn;
+	encioc_element_t *uelm;
+	enc_softc_t *enc;
+	enc_cache_t *cache;
+	void *addr;
+	int error, i;
+
+
+	if (arg_addr)
+		addr = *((caddr_t *) arg_addr);
+	else
+		addr = NULL;
+
+	periph = (struct cam_periph *)dev->si_drv1;
+	if (periph == NULL)
+		return (ENXIO);
+
+	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering encioctl\n"));
+
+	cam_periph_lock(periph);
+	enc = (struct enc_softc *)periph->softc;
+	cache = &enc->enc_cache;
+
+	/*
+	 * Now check to see whether we're initialized or not.
+	 * This actually should never fail as we're not supposed
+	 * to get past enc_open w/o successfully initializing
+	 * things.
+	 */
+	if ((enc->enc_flags & ENC_FLAG_INITIALIZED) == 0) {
+		cam_periph_unlock(periph);
+		return (ENXIO);
+	}
+	cam_periph_unlock(periph);
+
+	error = 0;
+
+	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
+	    ("trying to do ioctl %#lx\n", cmd));
+
+	/*
+	 * If this command can change the device's state,
+	 * we must have the device open for writing.
+	 *
+	 * For commands that get information about the
+	 * device- we don't need to lock the peripheral
+	 * if we aren't running a command.  The periph
+	 * also can't go away while a user process has
+	 * it open.
+	 */
+	switch (cmd) {
+	case ENCIOC_GETNELM:
+	case ENCIOC_GETELMMAP:
+	case ENCIOC_GETENCSTAT:
+	case ENCIOC_GETELMSTAT:
+	case ENCIOC_GETELMDESC:
+	case ENCIOC_GETELMDEVNAMES:
+		break;
+	default:
+		if ((flag & FWRITE) == 0) {
+			return (EBADF);
+		}
+	}
+ 
+	/*
+	 * XXX The values read here are only valid for the current
+	 *     configuration generation.  We need these ioctls
+	 *     to also pass in/out a generation number.
+	 */
+	sx_slock(&enc->enc_cache_lock);
+	switch (cmd) {
+	case ENCIOC_GETNELM:
+		error = copyout(&cache->nelms, addr, sizeof (cache->nelms));
+		break;
+		
+	case ENCIOC_GETELMMAP:
+		for (uelm = addr, i = 0; i != cache->nelms; i++) {
+			encioc_element_t kelm;
+			kelm.elm_idx = i;
+			kelm.elm_subenc_id = cache->elm_map[i].subenclosure;
+			kelm.elm_type = cache->elm_map[i].enctype;
+			error = copyout(&kelm, &uelm[i], sizeof(kelm));
+			if (error)
+				break;
+		}
+		break;
+
+	case ENCIOC_GETENCSTAT:
+		cam_periph_lock(periph);
+		error = enc->enc_vec.get_enc_status(enc, 1);
+		if (error) {
+			cam_periph_unlock(periph);
+			break;
+		}
+		tmp = cache->enc_status;
+		cam_periph_unlock(periph);
+		error = copyout(&tmp, addr, sizeof(tmp));
+		cache->enc_status = tmp;
+		break;
+
+	case ENCIOC_SETENCSTAT:
+		error = copyin(addr, &tmp, sizeof(tmp));
+		if (error)
+			break;
+		cam_periph_lock(periph);
+		error = enc->enc_vec.set_enc_status(enc, tmp, 1);
+		cam_periph_unlock(periph);
+		break;
+
+	case ENCIOC_GETSTRING:
+	case ENCIOC_SETSTRING:
+		if (enc->enc_vec.handle_string == NULL) {
+			error = EINVAL;
+			break;
+		}
+		error = copyin(addr, &sstr, sizeof(sstr));
+		if (error)
+			break;
+		cam_periph_lock(periph);
+		error = enc->enc_vec.handle_string(enc, &sstr, cmd);
+		cam_periph_unlock(periph);
+		break;
+
+	case ENCIOC_GETELMSTAT:
+		error = copyin(addr, &elms, sizeof(elms));
+		if (error)
+			break;
+		if (elms.elm_idx >= cache->nelms) {
+			error = EINVAL;
+			break;
+		}
+		cam_periph_lock(periph);
+		error = enc->enc_vec.get_elm_status(enc, &elms, 1);
+		cam_periph_unlock(periph);
+		if (error)
+			break;
+		error = copyout(&elms, addr, sizeof(elms));
+		break;
+
+	case ENCIOC_GETELMDESC:
+		error = copyin(addr, &elmd, sizeof(elmd));
+		if (error)
+			break;
+		if (elmd.elm_idx >= cache->nelms) {
+			error = EINVAL;
+			break;
+		}
+		if (enc->enc_vec.get_elm_desc != NULL) {
+			error = enc->enc_vec.get_elm_desc(enc, &elmd);
+			if (error)
+				break;
+		} else
+			elmd.elm_desc_len = 0;
+		error = copyout(&elmd, addr, sizeof(elmd));
+		break;
+
+	case ENCIOC_GETELMDEVNAMES:
+		if (enc->enc_vec.get_elm_devnames == NULL) {
+			error = EINVAL;
+			break;
+		}
+		error = copyin(addr, &elmdn, sizeof(elmdn));
+		if (error)
+			break;
+		if (elmdn.elm_idx >= cache->nelms) {
+			error = EINVAL;
+			break;
+		}
+		cam_periph_lock(periph);
+		error = (*enc->enc_vec.get_elm_devnames)(enc, &elmdn);
+		cam_periph_unlock(periph);
+		if (error)
+			break;
+		error = copyout(&elmdn, addr, sizeof(elmdn));
+		break;
+
+	case ENCIOC_SETELMSTAT:
+		error = copyin(addr, &elms, sizeof(elms));
+		if (error)
+			break;
+
+		if (elms.elm_idx >= cache->nelms) {
+			error = EINVAL;
+			break;
+		}
+		cam_periph_lock(periph);
+		error = enc->enc_vec.set_elm_status(enc, &elms, 1);
+		cam_periph_unlock(periph);
+
+		break;
+
+	case ENCIOC_INIT:
+
+		cam_periph_lock(periph);
+		error = enc->enc_vec.init_enc(enc);
+		cam_periph_unlock(periph);
+		break;
+
+	default:
+		cam_periph_lock(periph);
+		error = cam_periph_ioctl(periph, cmd, arg_addr, enc_error);
+		cam_periph_unlock(periph);
+		break;
+	}
+	sx_sunlock(&enc->enc_cache_lock);
+	return (error);
+}
+
+int
+enc_runcmd(struct enc_softc *enc, char *cdb, int cdbl, char *dptr, int *dlenp)
+{
+	int error, dlen, tdlen;
+	ccb_flags ddf;
+	union ccb *ccb;
+
+	CAM_DEBUG(enc->periph->path, CAM_DEBUG_TRACE,
+	    ("entering enc_runcmd\n"));
+	if (dptr) {
+		if ((dlen = *dlenp) < 0) {
+			dlen = -dlen;
+			ddf = CAM_DIR_OUT;
+		} else {
+			ddf = CAM_DIR_IN;
+		}
+	} else {
+		dlen = 0;
+		ddf = CAM_DIR_NONE;
+	}
+
+	if (cdbl > IOCDBLEN) {
+		cdbl = IOCDBLEN;
+	}
+
+	ccb = cam_periph_getccb(enc->periph, 1);
+	if (enc->enc_type == ENC_SEMB_SES || enc->enc_type == ENC_SEMB_SAFT) {
+		tdlen = min(dlen, 1020);
+		tdlen = (tdlen + 3) & ~3;
+		cam_fill_ataio(&ccb->ataio, 0, enc_done, ddf, 0, dptr, tdlen,
+		    30 * 1000);
+		if (cdb[0] == RECEIVE_DIAGNOSTIC)
+			ata_28bit_cmd(&ccb->ataio,
+			    ATA_SEP_ATTN, cdb[2], 0x02, tdlen / 4);
+		else if (cdb[0] == SEND_DIAGNOSTIC)
+			ata_28bit_cmd(&ccb->ataio,
+			    ATA_SEP_ATTN, dlen > 0 ? dptr[0] : 0,
+			    0x82, tdlen / 4);
+		else if (cdb[0] == READ_BUFFER)
+			ata_28bit_cmd(&ccb->ataio,
+			    ATA_SEP_ATTN, cdb[2], 0x00, tdlen / 4);
+		else
+			ata_28bit_cmd(&ccb->ataio,
+			    ATA_SEP_ATTN, dlen > 0 ? dptr[0] : 0,
+			    0x80, tdlen / 4);
+	} else {
+		tdlen = dlen;
+		cam_fill_csio(&ccb->csio, 0, enc_done, ddf, MSG_SIMPLE_Q_TAG,
+		    dptr, dlen, sizeof (struct scsi_sense_data), cdbl,
+		    60 * 1000);
+		bcopy(cdb, ccb->csio.cdb_io.cdb_bytes, cdbl);
+	}
+
+	error = cam_periph_runccb(ccb, enc_error, ENC_CFLAGS, ENC_FLAGS, NULL);
+	if (error) {
+		if (dptr) {
+			*dlenp = dlen;
+		}
+	} else {
+		if (dptr) {
+			if (ccb->ccb_h.func_code == XPT_ATA_IO)
+				*dlenp = ccb->ataio.resid;
+			else
+				*dlenp = ccb->csio.resid;
+			*dlenp += tdlen - dlen;
+		}
+	}
+	xpt_release_ccb(ccb);
+	CAM_DEBUG(enc->periph->path, CAM_DEBUG_SUBTRACE,
+	    ("exiting enc_runcmd: *dlenp = %d\n", *dlenp));
+	return (error);
+}
+
+void
+enc_log(struct enc_softc *enc, const char *fmt, ...)
+{
+	va_list ap;
+
+	printf("%s%d: ", enc->periph->periph_name, enc->periph->unit_number);
+	va_start(ap, fmt);
+	vprintf(fmt, ap);
+	va_end(ap);
+}
+
+/*
+ * The code after this point runs on many platforms,
+ * so forgive the slightly awkward and nonconforming
+ * appearance.
+ */
+
+/*
+ * Is this a device that supports enclosure services?
+ *
+ * It's a a pretty simple ruleset- if it is device type 0x0D (13), it's
+ * an ENC device. If it happens to be an old UNISYS SEN device, we can
+ * handle that too.
+ */
+
+#define	SAFTE_START	44
+#define	SAFTE_END	50
+#define	SAFTE_LEN	SAFTE_END-SAFTE_START
+
+static enctyp
+enc_type(struct ccb_getdev *cgd)
+{
+	int buflen;
+	unsigned char *iqd;
+
+	if (cgd->protocol == PROTO_SEMB) {
+		iqd = (unsigned char *)&cgd->ident_data;
+		if (STRNCMP(iqd + 43, "S-E-S", 5) == 0)
+			return (ENC_SEMB_SES);
+		else if (STRNCMP(iqd + 43, "SAF-TE", 6) == 0)
+			return (ENC_SEMB_SAFT);
+		return (ENC_NONE);
+
+	} else if (cgd->protocol != PROTO_SCSI)
+		return (ENC_NONE);
+
+	iqd = (unsigned char *)&cgd->inq_data;
+	buflen = min(sizeof(cgd->inq_data),
+	    SID_ADDITIONAL_LENGTH(&cgd->inq_data));
+	if (buflen < 8+SEN_ID_LEN)
+		return (ENC_NONE);
+
+	if ((iqd[0] & 0x1f) == T_ENCLOSURE) {
+		if (STRNCMP(&iqd[8], SEN_ID, SEN_ID_LEN) == 0) {
+			return (ENC_SEN);
+		} else if ((iqd[2] & 0x7) > 2) {
+			return (ENC_SES);
+		} else {
+			return (ENC_SES_SCSI2);
+		}
+		return (ENC_NONE);
+	}
+
+#ifdef	ENC_ENABLE_PASSTHROUGH
+	if ((iqd[6] & 0x40) && (iqd[2] & 0x7) >= 2) {
+		/*
+		 * PassThrough Device.
+		 */
+		return (ENC_ENC_PASSTHROUGH);
+	}
+#endif
+
+	/*
+	 * The comparison is short for a reason-
+	 * some vendors were chopping it short.
+	 */
+
+	if (buflen < SAFTE_END - 2) {
+		return (ENC_NONE);
+	}
+
+	if (STRNCMP((char *)&iqd[SAFTE_START], "SAF-TE", SAFTE_LEN - 2) == 0) {
+		return (ENC_SAFT);
+	}
+	return (ENC_NONE);
+}
+
+/*================== Enclosure Monitoring/Processing Daemon ==================*/
+/**
+ * \brief Queue an update request for a given action, if needed.
+ *
+ * \param enc		SES softc to queue the request for.
+ * \param action	Action requested.
+ */
+void
+enc_update_request(enc_softc_t *enc, uint32_t action)
+{
+	if ((enc->pending_actions & (0x1 << action)) == 0) {
+		enc->pending_actions |= (0x1 << action);
+		ENC_DLOG(enc, "%s: queing requested action %d\n",
+		    __func__, action);
+		if (enc->current_action == ENC_UPDATE_NONE)
+			wakeup(enc->enc_daemon);
+	} else {
+		ENC_DLOG(enc, "%s: ignoring requested action %d - "
+		    "Already queued\n", __func__, action);
+	}
+}
+
+/**
+ * \brief Invoke the handler of the highest priority pending
+ *	  state in the SES state machine.
+ *
+ * \param enc  The SES instance invoking the state machine.
+ */
+static void
+enc_fsm_step(enc_softc_t *enc)
+{
+	union ccb            *ccb;
+	uint8_t              *buf;
+	struct enc_fsm_state *cur_state;
+	int		      error;
+	uint32_t	      xfer_len;
+	
+	ENC_DLOG(enc, "%s enter %p\n", __func__, enc);
+
+	enc->current_action   = ffs(enc->pending_actions) - 1;
+	enc->pending_actions &= ~(0x1 << enc->current_action);
+
+	cur_state = &enc->enc_fsm_states[enc->current_action];
+
+	buf = NULL;
+	if (cur_state->buf_size != 0) {
+		cam_periph_unlock(enc->periph);
+		buf = malloc(cur_state->buf_size, M_SCSIENC, M_WAITOK|M_ZERO);
+		cam_periph_lock(enc->periph);
+	}
+
+	error = 0;
+	ccb   = NULL;
+	if (cur_state->fill != NULL) {
+		ccb = cam_periph_getccb(enc->periph, CAM_PRIORITY_NORMAL);
+
+		error = cur_state->fill(enc, cur_state, ccb, buf);
+		if (error != 0)
+			goto done;
+
+		error = cam_periph_runccb(ccb, cur_state->error,
+					  ENC_CFLAGS,
+					  ENC_FLAGS|SF_QUIET_IR, NULL);
+	}
+
+	if (ccb != NULL) {
+		if (ccb->ccb_h.func_code == XPT_ATA_IO)
+			xfer_len = ccb->ataio.dxfer_len - ccb->ataio.resid;
+		else
+			xfer_len = ccb->csio.dxfer_len - ccb->csio.resid;
+	} else
+		xfer_len = 0;
+
+	cam_periph_unlock(enc->periph);
+	cur_state->done(enc, cur_state, ccb, &buf, error, xfer_len);
+	cam_periph_lock(enc->periph);
+
+done:
+	ENC_DLOG(enc, "%s exit - result %d\n", __func__, error);
+	ENC_FREE_AND_NULL(buf);
+	if (ccb != NULL)
+		xpt_release_ccb(ccb);
+}
+
+/**
+ * \invariant Called with cam_periph mutex held.
+ */
+static void
+enc_status_updater(void *arg)
+{
+	enc_softc_t *enc;
+
+	enc = arg;
+	if (enc->enc_vec.poll_status != NULL)
+		enc->enc_vec.poll_status(enc);
+}
+
+static void
+enc_daemon(void *arg)
+{
+	enc_softc_t *enc;
+
+	enc = arg;
+
+	cam_periph_lock(enc->periph);
+	while ((enc->enc_flags & ENC_FLAG_SHUTDOWN) == 0) {
+		if (enc->pending_actions == 0) {
+			struct intr_config_hook *hook;
+
+			/*
+			 * Reset callout and msleep, or
+			 * issue timed task completion
+			 * status command.
+			 */
+			enc->current_action = ENC_UPDATE_NONE;
+
+			/*
+			 * We've been through our state machine at least
+			 * once.  Allow the transition to userland.
+			 */
+			hook = &enc->enc_boot_hold_ch;
+			if (hook->ich_func != NULL) {
+				config_intrhook_disestablish(hook);
+				hook->ich_func = NULL;
+			}
+
+			callout_reset(&enc->status_updater, 60*hz,
+				      enc_status_updater, enc);
+
+			cam_periph_sleep(enc->periph, enc->enc_daemon,
+					 PUSER, "idle", 0);
+		} else {
+			enc_fsm_step(enc);
+		}
+	}
+	enc->enc_daemon = NULL;
+	cam_periph_unlock(enc->periph);
+	cam_periph_release(enc->periph);
+	kproc_exit(0);
+}
+
+static int
+enc_kproc_init(enc_softc_t *enc)
+{
+	int result;
+
+	callout_init_mtx(&enc->status_updater, enc->periph->sim->mtx, 0);
+
+	if (cam_periph_acquire(enc->periph) != CAM_REQ_CMP)
+		return (ENXIO);
+
+	result = kproc_create(enc_daemon, enc, &enc->enc_daemon, /*flags*/0,
+			      /*stackpgs*/0, "enc_daemon%d",
+			      enc->periph->unit_number);
+	if (result == 0) {
+		/* Do an initial load of all page data. */
+		cam_periph_lock(enc->periph);
+		enc->enc_vec.poll_status(enc);
+		cam_periph_unlock(enc->periph);
+	} else
+		cam_periph_release(enc->periph);
+	return (result);
+}
+ 
+/**
+ * \brief Interrupt configuration hook callback associated with
+ *        enc_boot_hold_ch.
+ *
+ * Since interrupts are always functional at the time of enclosure
+ * configuration, there is nothing to be done when the callback occurs.
+ * This hook is only registered to hold up boot processing while initial
+ * eclosure processing occurs.
+ * 
+ * \param arg  The enclosure softc, but currently unused in this callback.
+ */
+static void
+enc_nop_confighook_cb(void *arg __unused)
+{
+}
+
+static cam_status
+enc_ctor(struct cam_periph *periph, void *arg)
+{
+	cam_status status = CAM_REQ_CMP_ERR;
+	int err;
+	enc_softc_t *enc;
+	struct ccb_getdev *cgd;
+	char *tname;
+
+	cgd = (struct ccb_getdev *)arg;
+	if (periph == NULL) {
+		printf("enc_ctor: periph was NULL!!\n");
+		goto out;
+	}
+
+	if (cgd == NULL) {
+		printf("enc_ctor: no getdev CCB, can't register device\n");
+		goto out;
+	}
+
+	enc = ENC_MALLOCZ(sizeof(*enc));
+	if (enc == NULL) {
+		printf("enc_ctor: Unable to probe new device. "
+		       "Unable to allocate enc\n");				
+		goto out;
+	}
+	enc->periph = periph;
+	enc->current_action = ENC_UPDATE_INVALID;
+
+	enc->enc_type = enc_type(cgd);
+	sx_init(&enc->enc_cache_lock, "enccache");
+
+	switch (enc->enc_type) {
+	case ENC_SES:
+	case ENC_SES_SCSI2:
+	case ENC_SES_PASSTHROUGH:
+	case ENC_SEMB_SES:
+		err = ses_softc_init(enc);
+		break;
+	case ENC_SAFT:
+	case ENC_SEMB_SAFT:
+		err = safte_softc_init(enc);
+		break;
+	case ENC_SEN:
+	case ENC_NONE:
+	default:
+		ENC_FREE(enc);
+		return (CAM_REQ_CMP_ERR);
+	}
+
+	if (err) {
+		xpt_print(periph->path, "error %d initializing\n", err);
+		goto out;
+	}
+
+	/*
+	 * Hold off userland until we have made at least one pass
+	 * through our state machine so that physical path data is
+	 * present.
+	 */
+	if (enc->enc_vec.poll_status != NULL) {
+		enc->enc_boot_hold_ch.ich_func = enc_nop_confighook_cb;
+		enc->enc_boot_hold_ch.ich_arg = enc;
+		config_intrhook_establish(&enc->enc_boot_hold_ch);
+	}
+
+	/*
+	 * The softc field is set only once the enc is fully initialized
+	 * so that we can rely on this field to detect partially
+	 * initialized periph objects in the AC_FOUND_DEVICE handler.
+	 */
+	periph->softc = enc;
+
+	cam_periph_unlock(periph);
+	if (enc->enc_vec.poll_status != NULL) {
+		err = enc_kproc_init(enc);
+		if (err) {
+			xpt_print(periph->path,
+				  "error %d starting enc_daemon\n", err);
+			goto out;
+		}
+	}
+
+	if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
+		xpt_print(periph->path, "%s: lost periph during "
+			  "registration!\n", __func__);
+		cam_periph_lock(periph);
+
+		return (CAM_REQ_CMP_ERR);
+	}
+
+	enc->enc_dev = make_dev(&enc_cdevsw, periph->unit_number,
+	    UID_ROOT, GID_OPERATOR, 0600, "%s%d",
+	    periph->periph_name, periph->unit_number);
+
+	cam_periph_lock(periph);
+	enc->enc_dev->si_drv1 = periph;
+
+	enc->enc_flags |= ENC_FLAG_INITIALIZED;
+
+	/*
+	 * Add an async callback so that we get notified if this
+	 * device goes away.
+	 */
+	xpt_register_async(AC_LOST_DEVICE, enc_async, periph, periph->path);
+
+	switch (enc->enc_type) {
+	default:
+	case ENC_NONE:
+		tname = "No ENC device";
+		break;
+	case ENC_SES_SCSI2:
+		tname = "SCSI-2 ENC Device";
+		break;
+	case ENC_SES:
+		tname = "SCSI-3 ENC Device";
+		break;
+        case ENC_SES_PASSTHROUGH:
+		tname = "ENC Passthrough Device";
+		break;
+        case ENC_SEN:
+		tname = "UNISYS SEN Device (NOT HANDLED YET)";
+		break;
+        case ENC_SAFT:
+		tname = "SAF-TE Compliant Device";
+		break;
+	case ENC_SEMB_SES:
+		tname = "SEMB SES Device";
+		break;
+	case ENC_SEMB_SAFT:
+		tname = "SEMB SAF-TE Device";
+		break;
+	}
+	xpt_announce_periph(periph, tname);
+	status = CAM_REQ_CMP;
+
+out:
+	if (status != CAM_REQ_CMP)
+		enc_dtor(periph);
+	return (status);
+}
+
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/scsi/scsi_enc.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/cam/scsi/scsi_enc.h	Wed Jul 25 16:45:04 2012 +0300
@@ -0,0 +1,219 @@
+/* $FreeBSD: head/sys/cam/scsi/scsi_enc.h 235911 2012-05-24 14:07:44Z mav $ */
+/*-
+ * Copyright (c) 2000 by Matthew Jacob
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * the GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#ifndef	_SCSI_ENC_H_
+#define	_SCSI_ENC_H_
+
+#include <cam/scsi/scsi_ses.h>
+
+#define	ENCIOC			('s' - 040)
+#define	ENCIOC_GETNELM		_IO(ENCIOC, 1)
+#define	ENCIOC_GETELMMAP	_IO(ENCIOC, 2)
+#define	ENCIOC_GETENCSTAT	_IO(ENCIOC, 3)
+#define	ENCIOC_SETENCSTAT	_IO(ENCIOC, 4)
+#define	ENCIOC_GETELMSTAT	_IO(ENCIOC, 5)
+#define	ENCIOC_SETELMSTAT	_IO(ENCIOC, 6)
+#define	ENCIOC_GETTEXT		_IO(ENCIOC, 7)
+#define	ENCIOC_INIT		_IO(ENCIOC, 8)
+#define	ENCIOC_GETELMDESC	_IO(ENCIOC, 9)
+#define	ENCIOC_GETELMDEVNAMES	_IO(ENCIOC, 10)
+#define	ENCIOC_GETSTRING	_IO(ENCIOC, 11)
+#define	ENCIOC_SETSTRING	_IO(ENCIOC, 12)
+
+/*
+ * Platform Independent Definitions for enclosure devices.
+ */
+/*
+ * SCSI Based Environmental Services Application Defines
+ *
+ * Based almost entirely on SCSI-3 ENC Revision 8A specification,
+ * but slightly abstracted as the underlying device may in fact
+ * be a SAF-TE or vendor unique device.
+ */
+/*
+ * ENC Driver Operations:
+ * (The defines themselves are platform and access method specific)
+ *
+ * ENCIOC_GETNELM
+ * ENCIOC_GETELMMAP
+ * ENCIOC_GETENCSTAT
+ * ENCIOC_SETENCSTAT
+ * ENCIOC_GETELMSTAT
+ * ENCIOC_SETELMSTAT
+ * ENCIOC_INIT
+ *
+ *
+ * An application finds out how many elements an enclosure instance
+ * is managing by performing a ENCIOC_GETNELM operation. It then
+ * performs a ENCIOC_GETELMMAP to get the map that contains the
+ * elment identifiers for all elements (see encioc_element_t below).
+ * This information is static.
+ * 
+ * The application may perform ENCIOC_GETELMSTAT operations to retrieve
+ * status on an element (see the enc_elm_status_t structure below),
+ * ENCIOC_SETELMSTAT operations to set status for an element.
+ *
+ * Similarly, overall enclosure status me be fetched or set via
+ * ENCIOC_GETENCSTAT or  ENCIOC_SETENCSTAT operations (see encioc_enc_status_t
+ * below).
+ *
+ * Readers should note that there is nothing that requires either a set
+ * or a clear operation to actually latch and do anything in the target.
+ *
+ * A ENCIOC_INIT operation causes the enclosure to be initialized.
+ */
+
+/* Element Types */
+typedef enum {
+	ELMTYP_UNSPECIFIED	= 0x00,
+	ELMTYP_DEVICE		= 0x01,
+	ELMTYP_POWER		= 0x02,
+	ELMTYP_FAN		= 0x03,
+	ELMTYP_THERM		= 0x04,
+	ELMTYP_DOORLOCK		= 0x05,
+	ELMTYP_ALARM		= 0x06,
+	ELMTYP_ESCC		= 0x07,	/* Enclosure SCC */
+	ELMTYP_SCC		= 0x08,	/* SCC */
+	ELMTYP_NVRAM		= 0x09,
+	ELMTYP_INV_OP_REASON    = 0x0a,
+	ELMTYP_UPS		= 0x0b,
+	ELMTYP_DISPLAY		= 0x0c,
+	ELMTYP_KEYPAD		= 0x0d,
+	ELMTYP_ENCLOSURE	= 0x0e,
+	ELMTYP_SCSIXVR		= 0x0f,
+	ELMTYP_LANGUAGE		= 0x10,
+	ELMTYP_COMPORT		= 0x11,
+	ELMTYP_VOM		= 0x12,
+	ELMTYP_AMMETER		= 0x13,
+	ELMTYP_SCSI_TGT		= 0x14,
+	ELMTYP_SCSI_INI		= 0x15,
+	ELMTYP_SUBENC		= 0x16,
+	ELMTYP_ARRAY_DEV	= 0x17,
+	ELMTYP_SAS_EXP		= 0x18, /* SAS expander */
+	ELMTYP_SAS_CONN		= 0x19  /* SAS connector */
+} elm_type_t;
+
+typedef struct encioc_element {
+	/* Element Index */
+	unsigned int	elm_idx;	
+
+	/* ID of SubEnclosure containing Element*/
+	unsigned int	elm_subenc_id;
+
+	/* Element Type */
+	elm_type_t	elm_type;
+} encioc_element_t;
+
+/*
+ * Overall Enclosure Status
+ */
+typedef unsigned char encioc_enc_status_t;
+
+/*
+ * Element Status
+ */
+typedef struct encioc_elm_status {
+	unsigned int	elm_idx;
+	unsigned char	cstat[4];
+} encioc_elm_status_t;
+
+/*
+ * ENC String structure, for StringIn and StringOut commands; use this with
+ * the ENCIOC_GETSTRING and ENCIOC_SETSTRING ioctls.
+ */
+typedef struct encioc_string {
+	size_t bufsiz;		/* IN/OUT: length of string provided/returned */
+#define	ENC_STRING_MAX	0xffff
+	uint8_t *buf;		/* IN/OUT: string */
+} encioc_string_t;
+
+/*============================================================================*/
+
+/* 
+ * SES v2 r20 6.1.10 (pg 39) - Element Descriptor diagnostic page
+ * Tables 21, 22, and 23
+ */
+typedef struct encioc_elm_desc {
+	unsigned int	 elm_idx;       /* IN: elment requested */
+	uint16_t	 elm_desc_len; /* IN: buffer size; OUT: bytes written */
+	char		*elm_desc_str; /* IN/OUT: buffer for descriptor data */
+} encioc_elm_desc_t;
+
+/*
+ * ENCIOC_GETELMDEVNAMES:
+ * ioctl structure to get an element's device names, if available
+ */
+typedef struct  encioc_elm_devnames {
+	unsigned int	 elm_idx;	/* IN: element index */
+	size_t		 elm_names_size;/* IN: size of elm_devnames */
+	size_t		 elm_names_len;	/* OUT: actual size returned */
+	/*
+	 * IN/OUT: comma separated list of peripheral driver
+	 * instances servicing this element.
+	 */
+	char		*elm_devnames;
+} encioc_elm_devnames_t;
+
+/* ioctl structure for requesting FC info for a port */
+typedef struct encioc_elm_fc_port {
+	unsigned int		elm_idx;
+	unsigned int		port_idx;
+	struct ses_elm_fc_port	port_data;
+} encioc_elm_fc_port_t;
+
+/* ioctl structure for requesting SAS info for element phys */
+typedef struct encioc_elm_sas_device_phy {
+	unsigned int			elm_idx;
+	unsigned int			phy_idx;
+	struct ses_elm_sas_device_phy	phy_data;
+} enioc_elm_sas_phy_t;
+
+/* ioctl structure for requesting SAS info for an expander phy */
+typedef struct encioc_elm_sas_expander_phy {
+	unsigned int			elm_idx;
+	unsigned int			phy_idx;
+	struct ses_elm_sas_expander_phy phy_data;
+} encioc_elm_sas_expander_phy_t;
+
+/* ioctl structure for requesting SAS info for a port phy */
+typedef struct encioc_elm_sas_port_phy {
+	unsigned int			elm_idx;
+	unsigned int			phy_idx;
+	struct ses_elm_sas_port_phy	phy_data;
+} enioc_elm_sas_port_phy_t;
+
+/* ioctl structure for requesting additional status for an element */
+typedef struct encioc_addl_status {
+	unsigned int			   elm_idx;
+	union ses_elm_addlstatus_descr_hdr addl_hdr;
+	union ses_elm_addlstatus_proto_hdr proto_hdr;
+} enioc_addl_status_t;
+
+#endif /* _SCSI_ENC_H_ */
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/scsi/scsi_enc_internal.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/cam/scsi/scsi_enc_internal.h	Wed Jul 25 16:45:04 2012 +0300
@@ -0,0 +1,230 @@
+/*-
+ * Copyright (c) 2000 Matthew Jacob
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/sys/cam/scsi/scsi_enc_internal.h 235911 2012-05-24 14:07:44Z mav $
+ */
+
+/*
+ * This file contains definitions only intended for use within
+ * sys/cam/scsi/scsi_enc*.c, and not in other kernel components.
+ */
+
+#ifndef	__SCSI_ENC_INTERNAL_H__
+#define	__SCSI_ENC_INTERNAL_H__
+
+typedef struct enc_element {
+	uint32_t
+		 enctype	: 8,	/* enclosure type */
+		 subenclosure : 8,	/* subenclosure id */
+		 svalid	: 1,		/* enclosure information valid */
+		 overall_status_elem: 1,/*
+					 * This object represents generic
+					 * status about all objects of this
+					 * type.
+					 */
+		 priv	: 14;		/* private data, per object */
+	uint8_t	 encstat[4];		/* state && stats */
+	uint8_t *physical_path;		/* Device physical path data. */
+	u_int    physical_path_len;	/* Length of device path data. */
+	void    *elm_private;		/* per-type object data */
+} enc_element_t;
+
+typedef enum {
+	ENC_NONE,
+	ENC_SES_SCSI2,
+	ENC_SES,
+	ENC_SES_PASSTHROUGH,
+	ENC_SEN,
+	ENC_SAFT,
+	ENC_SEMB_SES,
+	ENC_SEMB_SAFT
+} enctyp;
+
+/* Platform Independent Driver Internal Definitions for enclosure devices. */
+typedef struct enc_softc enc_softc_t;
+
+struct enc_fsm_state;
+typedef int fsm_fill_handler_t(enc_softc_t *ssc,
+				struct enc_fsm_state *state,
+				union ccb *ccb,
+				uint8_t *buf);
+typedef int fsm_error_handler_t(union ccb *ccb, uint32_t cflags,
+				uint32_t sflags);
+typedef int fsm_done_handler_t(enc_softc_t *ssc,
+			       struct enc_fsm_state *state, union ccb *ccb,
+			       uint8_t **bufp, int error, int xfer_len);
+
+struct enc_fsm_state {
+	const char	    *name;
+	int		     page_code;
+	size_t		     buf_size;
+	uint32_t	     timeout;
+	fsm_fill_handler_t  *fill;
+	fsm_done_handler_t  *done;
+	fsm_error_handler_t *error;
+};
+
+typedef int (enc_softc_init_t)(enc_softc_t *);
+typedef void (enc_softc_invalidate_t)(enc_softc_t *);
+typedef void (enc_softc_cleanup_t)(enc_softc_t *);
+typedef int (enc_init_enc_t)(enc_softc_t *); 
+typedef int (enc_get_enc_status_t)(enc_softc_t *, int);
+typedef int (enc_set_enc_status_t)(enc_softc_t *, encioc_enc_status_t, int);
+typedef int (enc_get_elm_status_t)(enc_softc_t *, encioc_elm_status_t *, int);
+typedef int (enc_set_elm_status_t)(enc_softc_t *, encioc_elm_status_t *, int);
+typedef int (enc_get_elm_desc_t)(enc_softc_t *, encioc_elm_desc_t *); 
+typedef int (enc_get_elm_devnames_t)(enc_softc_t *, encioc_elm_devnames_t *); 
+typedef int (enc_handle_string_t)(enc_softc_t *, encioc_string_t *, int);
+typedef void (enc_device_found_t)(enc_softc_t *);
+typedef void (enc_poll_status_t)(enc_softc_t *);
+
+struct enc_vec {
+	enc_softc_invalidate_t	*softc_invalidate;
+	enc_softc_cleanup_t	*softc_cleanup;
+	enc_init_enc_t		*init_enc;
+	enc_get_enc_status_t	*get_enc_status;
+	enc_set_enc_status_t	*set_enc_status;
+	enc_get_elm_status_t	*get_elm_status;
+	enc_set_elm_status_t	*set_elm_status;
+	enc_get_elm_desc_t	*get_elm_desc;
+	enc_get_elm_devnames_t	*get_elm_devnames;
+	enc_handle_string_t	*handle_string;
+	enc_device_found_t	*device_found;
+	enc_poll_status_t	*poll_status;
+};
+
+typedef struct enc_cache {
+	enc_element_t		*elm_map;	/* objects */
+	int			 nelms;		/* number of objects */
+	encioc_enc_status_t	 enc_status;	/* overall status */
+	void			*private;	/* per-type private data */
+} enc_cache_t;
+
+/* Enclosure instance toplevel structure */
+struct enc_softc {
+	enctyp			 enc_type;	/* type of enclosure */
+	struct enc_vec		 enc_vec;	/* vector to handlers */
+	void			*enc_private;	/* per-type private data */
+
+	/**
+	 * "Published" configuration and state data available to
+	 * external consumers.
+	 */
+	enc_cache_t		 enc_cache;
+
+	/**
+	 * Configuration and state data being actively updated
+	 * by the enclosure daemon.
+	 */
+	enc_cache_t		 enc_daemon_cache;
+
+	struct sx		 enc_cache_lock;
+	uint8_t			 enc_flags;
+#define	ENC_FLAG_INVALID	0x01
+#define	ENC_FLAG_INITIALIZED	0x02
+#define	ENC_FLAG_SHUTDOWN	0x04
+	union ccb		 saved_ccb;
+	struct cdev		*enc_dev;
+	struct cam_periph	*periph;
+
+	/* Bitmap of pending operations. */
+	uint32_t		 pending_actions;
+
+	/* The action on which the state machine is currently working. */
+	uint32_t		 current_action;
+#define	ENC_UPDATE_NONE		0x00
+#define	ENC_UPDATE_INVALID	0xff
+
+	/* Callout for auto-updating enclosure status */
+	struct callout		 status_updater;
+
+	struct proc		*enc_daemon;
+
+	struct enc_fsm_state 	*enc_fsm_states;
+
+	struct intr_config_hook  enc_boot_hold_ch;
+};
+
+static inline enc_cache_t *
+enc_other_cache(enc_softc_t *enc, enc_cache_t *primary)
+{
+	return (primary == &enc->enc_cache
+	      ? &enc->enc_daemon_cache : &enc->enc_cache);
+}
+
+/* SES Management mode page - SES2r20 Table 59 */
+struct ses_mgmt_mode_page {
+	struct scsi_mode_header_6 header;
+	struct scsi_mode_blk_desc blk_desc;
+	uint8_t byte0;  /* ps : 1, spf : 1, page_code : 6 */
+#define SES_MGMT_MODE_PAGE_CODE 0x14
+	uint8_t length;
+#define SES_MGMT_MODE_PAGE_LEN  6
+	uint8_t reserved[3];
+	uint8_t byte5;  /* reserved : 7, enbltc : 1 */
+#define SES_MGMT_TIMED_COMP_EN  0x1
+	uint8_t max_comp_time[2];
+};
+
+/* Enclosure core interface for sub-drivers */
+int  enc_runcmd(struct enc_softc *, char *, int, char *, int *);
+void enc_log(struct enc_softc *, const char *, ...);
+void enc_done(struct cam_periph *, union ccb *);
+int  enc_error(union ccb *, uint32_t, uint32_t);
+void enc_update_request(enc_softc_t *, uint32_t);
+
+/* SES Native interface */
+enc_softc_init_t	ses_softc_init;
+
+/* SAF-TE interface */
+enc_softc_init_t	safte_softc_init;
+
+/* Helper macros */
+MALLOC_DECLARE(M_SCSIENC);
+#define	ENC_CFLAGS		CAM_RETRY_SELTO
+#define	ENC_FLAGS		SF_NO_PRINT | SF_RETRY_UA
+#define	STRNCMP			strncmp
+#define	PRINTF			printf
+#define	ENC_LOG			enc_log
+#if defined(DEBUG) || defined(ENC_DEBUG)
+#define	ENC_DLOG		enc_log
+#else
+#define	ENC_DLOG		if (0) enc_log
+#endif
+#define	ENC_VLOG		if (bootverbose) enc_log
+#define	ENC_MALLOC(amt)		malloc(amt, M_SCSIENC, M_NOWAIT)
+#define	ENC_MALLOCZ(amt)	malloc(amt, M_SCSIENC, M_ZERO|M_NOWAIT)
+/* Cast away const avoiding GCC warnings. */
+#define	ENC_FREE(ptr)		free((void *)((uintptr_t)ptr), M_SCSIENC)
+#define	ENC_FREE_AND_NULL(ptr)	do {	\
+	if (ptr != NULL) {		\
+		ENC_FREE(ptr);		\
+		ptr = NULL;		\
+	}				\
+} while(0)
+#define	MEMZERO			bzero
+#define	MEMCPY(dest, src, amt)	bcopy(src, dest, amt)
+
+#endif	/* __SCSI_ENC_INTERNAL_H__ */
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/scsi/scsi_enc_safte.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/cam/scsi/scsi_enc_safte.c	Wed Jul 25 16:45:04 2012 +0300
@@ -0,0 +1,1137 @@
+/*-
+ * Copyright (c) 2000 Matthew Jacob
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_enc_safte.c 235911 2012-05-24 14:07:44Z mav $");
+
+#include <sys/param.h>
+
+#include <sys/conf.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/sx.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_periph.h>
+
+#include <cam/scsi/scsi_enc.h>
+#include <cam/scsi/scsi_enc_internal.h>
+#include <cam/scsi/scsi_message.h>
+
+#include <opt_enc.h>
+
+/*
+ * SAF-TE Type Device Emulation
+ */
+
+static int safte_set_enc_status(enc_softc_t *enc, uint8_t encstat, int slpflag);
+
+#define	ALL_ENC_STAT (SES_ENCSTAT_CRITICAL | SES_ENCSTAT_UNRECOV | \
+	SES_ENCSTAT_NONCRITICAL | SES_ENCSTAT_INFO)
+/*
+ * SAF-TE specific defines- Mandatory ones only...
+ */
+
+/*
+ * READ BUFFER ('get' commands) IDs- placed in offset 2 of cdb
+ */
+#define	SAFTE_RD_RDCFG	0x00	/* read enclosure configuration */
+#define	SAFTE_RD_RDESTS	0x01	/* read enclosure status */
+#define	SAFTE_RD_RDDSTS	0x04	/* read drive slot status */
+#define	SAFTE_RD_RDGFLG	0x05	/* read global flags */
+
+/*
+ * WRITE BUFFER ('set' commands) IDs- placed in offset 0 of databuf
+ */
+#define	SAFTE_WT_DSTAT	0x10	/* write device slot status */
+#define	SAFTE_WT_SLTOP	0x12	/* perform slot operation */
+#define	SAFTE_WT_FANSPD	0x13	/* set fan speed */
+#define	SAFTE_WT_ACTPWS	0x14	/* turn on/off power supply */
+#define	SAFTE_WT_GLOBAL	0x15	/* send global command */
+
+#define	SAFT_SCRATCH	64
+#define	SCSZ		0x8000
+
+typedef enum {
+	SAFTE_UPDATE_NONE,
+	SAFTE_UPDATE_READCONFIG,
+	SAFTE_UPDATE_READGFLAGS,
+	SAFTE_UPDATE_READENCSTATUS,
+	SAFTE_UPDATE_READSLOTSTATUS,
+	SAFTE_PROCESS_CONTROL_REQS,
+	SAFTE_NUM_UPDATE_STATES
+} safte_update_action;
+
+static fsm_fill_handler_t safte_fill_read_buf_io;
+static fsm_fill_handler_t safte_fill_control_request;
+static fsm_done_handler_t safte_process_config;
+static fsm_done_handler_t safte_process_gflags;
+static fsm_done_handler_t safte_process_status;
+static fsm_done_handler_t safte_process_slotstatus;
+static fsm_done_handler_t safte_process_control_request;
+
+static struct enc_fsm_state enc_fsm_states[SAFTE_NUM_UPDATE_STATES] =
+{
+	{ "SAFTE_UPDATE_NONE", 0, 0, 0, NULL, NULL, NULL },
+	{
+		"SAFTE_UPDATE_READCONFIG",
+		SAFTE_RD_RDCFG,
+		SAFT_SCRATCH,
+		60 * 1000,
+		safte_fill_read_buf_io,
+		safte_process_config,
+		enc_error
+	},
+	{
+		"SAFTE_UPDATE_READGFLAGS",
+		SAFTE_RD_RDGFLG,
+		16,
+		60 * 1000,
+		safte_fill_read_buf_io,
+		safte_process_gflags,
+		enc_error
+	},
+	{
+		"SAFTE_UPDATE_READENCSTATUS",
+		SAFTE_RD_RDESTS,
+		SCSZ,
+		60 * 1000,
+		safte_fill_read_buf_io,
+		safte_process_status,
+		enc_error
+	},
+	{
+		"SAFTE_UPDATE_READSLOTSTATUS",
+		SAFTE_RD_RDDSTS,
+		SCSZ,
+		60 * 1000,
+		safte_fill_read_buf_io,
+		safte_process_slotstatus,
+		enc_error
+	},
+	{
+		"SAFTE_PROCESS_CONTROL_REQS",
+		0,
+		SCSZ,
+		60 * 1000,
+		safte_fill_control_request,
+		safte_process_control_request,
+		enc_error
+	}
+};
+
+typedef struct safte_control_request {
+	int	elm_idx;
+	uint8_t	elm_stat[4];
+	int	result;
+	TAILQ_ENTRY(safte_control_request) links;
+} safte_control_request_t;
+TAILQ_HEAD(safte_control_reqlist, safte_control_request);
+typedef struct safte_control_reqlist safte_control_reqlist_t;
+enum {
+	SES_SETSTATUS_ENC_IDX = -1
+};
+
+static void
+safte_terminate_control_requests(safte_control_reqlist_t *reqlist, int result)
+{
+	safte_control_request_t *req;
+
+	while ((req = TAILQ_FIRST(reqlist)) != NULL) {
+		TAILQ_REMOVE(reqlist, req, links);
+		req->result = result;
+		wakeup(req);
+	}
+}
+
+struct scfg {
+	/*
+	 * Cached Configuration
+	 */
+	uint8_t	Nfans;		/* Number of Fans */
+	uint8_t	Npwr;		/* Number of Power Supplies */
+	uint8_t	Nslots;		/* Number of Device Slots */
+	uint8_t	DoorLock;	/* Door Lock Installed */
+	uint8_t	Ntherm;		/* Number of Temperature Sensors */
+	uint8_t	Nspkrs;		/* Number of Speakers */
+	uint8_t	Ntstats;	/* Number of Thermostats */
+	/*
+	 * Cached Flag Bytes for Global Status
+	 */
+	uint8_t	flag1;
+	uint8_t	flag2;
+	/*
+	 * What object index ID is where various slots start.
+	 */
+	uint8_t	pwroff;
+	uint8_t	slotoff;
+#define	SAFT_ALARM_OFFSET(cc)	(cc)->slotoff - 1
+
+	encioc_enc_status_t	adm_status;
+	encioc_enc_status_t	enc_status;
+	encioc_enc_status_t	slot_status;
+
+	safte_control_reqlist_t	requests;
+	safte_control_request_t	*current_request;
+	int			current_request_stage;
+	int			current_request_stages;
+};
+
+#define	SAFT_FLG1_ALARM		0x1
+#define	SAFT_FLG1_GLOBFAIL	0x2
+#define	SAFT_FLG1_GLOBWARN	0x4
+#define	SAFT_FLG1_ENCPWROFF	0x8
+#define	SAFT_FLG1_ENCFANFAIL	0x10
+#define	SAFT_FLG1_ENCPWRFAIL	0x20
+#define	SAFT_FLG1_ENCDRVFAIL	0x40
+#define	SAFT_FLG1_ENCDRVWARN	0x80
+
+#define	SAFT_FLG2_LOCKDOOR	0x4
+#define	SAFT_PRIVATE		sizeof (struct scfg)
+
+static char *safte_2little = "Too Little Data Returned (%d) at line %d\n";
+#define	SAFT_BAIL(r, x)	\
+	if ((r) >= (x)) { \
+		ENC_LOG(enc, safte_2little, x, __LINE__);\
+		return (EIO); \
+	}
+
+int emulate_array_devices = 1;
+SYSCTL_DECL(_kern_cam_enc);
+SYSCTL_INT(_kern_cam_enc, OID_AUTO, emulate_array_devices, CTLFLAG_RW,
+           &emulate_array_devices, 0, "Emulate Array Devices for SAF-TE");
+TUNABLE_INT("kern.cam.enc.emulate_array_devices", &emulate_array_devices);
+
+static int
+safte_fill_read_buf_io(enc_softc_t *enc, struct enc_fsm_state *state,
+		       union ccb *ccb, uint8_t *buf)
+{
+
+	if (state->page_code != SAFTE_RD_RDCFG &&
+	    enc->enc_cache.nelms == 0) {
+		enc_update_request(enc, SAFTE_UPDATE_READCONFIG);
+		return (-1);
+	}
+
+	if (enc->enc_type == ENC_SEMB_SAFT) {
+		semb_read_buffer(&ccb->ataio, /*retries*/5,
+				enc_done, MSG_SIMPLE_Q_TAG,
+				state->page_code, buf, state->buf_size,
+				state->timeout);
+	} else {
+		scsi_read_buffer(&ccb->csio, /*retries*/5,
+				enc_done, MSG_SIMPLE_Q_TAG, 1,
+				state->page_code, 0, buf, state->buf_size,
+				SSD_FULL_SIZE, state->timeout);
+	}
+	return (0);
+}
+
+static int
+safte_process_config(enc_softc_t *enc, struct enc_fsm_state *state,
+    union ccb *ccb, uint8_t **bufp, int error, int xfer_len)
+{
+	struct scfg *cfg;
+	uint8_t *buf = *bufp;
+	int i, r;
+
+	cfg = enc->enc_private;
+	if (cfg == NULL)
+		return (ENXIO);
+	if (error != 0)
+		return (error);
+	if (xfer_len < 6) {
+		ENC_LOG(enc, "too little data (%d) for configuration\n",
+		    xfer_len);
+		return (EIO);
+	}
+	cfg->Nfans = buf[0];
+	cfg->Npwr = buf[1];
+	cfg->Nslots = buf[2];
+	cfg->DoorLock = buf[3];
+	cfg->Ntherm = buf[4];
+	cfg->Nspkrs = buf[5];
+	if (xfer_len >= 7)
+		cfg->Ntstats = buf[6] & 0x0f;
+	else
+		cfg->Ntstats = 0;
+	ENC_VLOG(enc, "Nfans %d Npwr %d Nslots %d Lck %d Ntherm %d Nspkrs %d "
+	    "Ntstats %d\n",
+	    cfg->Nfans, cfg->Npwr, cfg->Nslots, cfg->DoorLock, cfg->Ntherm,
+	    cfg->Nspkrs, cfg->Ntstats);
+
+	enc->enc_cache.nelms = cfg->Nfans + cfg->Npwr + cfg->Nslots +
+	    cfg->DoorLock + cfg->Ntherm + cfg->Nspkrs + cfg->Ntstats + 1;
+	ENC_FREE_AND_NULL(enc->enc_cache.elm_map);
+	enc->enc_cache.elm_map =
+	    ENC_MALLOCZ(enc->enc_cache.nelms * sizeof(enc_element_t));
+	if (enc->enc_cache.elm_map == NULL) {
+		enc->enc_cache.nelms = 0;
+		return (ENOMEM);
+	}
+
+	r = 0;
+	/*
+	 * Note that this is all arranged for the convenience
+	 * in later fetches of status.
+	 */
+	for (i = 0; i < cfg->Nfans; i++)
+		enc->enc_cache.elm_map[r++].enctype = ELMTYP_FAN;
+	cfg->pwroff = (uint8_t) r;
+	for (i = 0; i < cfg->Npwr; i++)
+		enc->enc_cache.elm_map[r++].enctype = ELMTYP_POWER;
+	for (i = 0; i < cfg->DoorLock; i++)
+		enc->enc_cache.elm_map[r++].enctype = ELMTYP_DOORLOCK;
+	if (cfg->Nspkrs > 0)
+		enc->enc_cache.elm_map[r++].enctype = ELMTYP_ALARM;
+	for (i = 0; i < cfg->Ntherm; i++)
+		enc->enc_cache.elm_map[r++].enctype = ELMTYP_THERM;
+	for (i = 0; i <= cfg->Ntstats; i++)
+		enc->enc_cache.elm_map[r++].enctype = ELMTYP_THERM;
+	cfg->slotoff = (uint8_t) r;
+	for (i = 0; i < cfg->Nslots; i++)
+		enc->enc_cache.elm_map[r++].enctype =
+		    emulate_array_devices ? ELMTYP_ARRAY_DEV :
+		     ELMTYP_DEVICE;
+
+	enc_update_request(enc, SAFTE_UPDATE_READGFLAGS);
+	enc_update_request(enc, SAFTE_UPDATE_READENCSTATUS);
+	enc_update_request(enc, SAFTE_UPDATE_READSLOTSTATUS);
+
+	return (0);
+}
+
+static int
+safte_process_gflags(enc_softc_t *enc, struct enc_fsm_state *state,
+    union ccb *ccb, uint8_t **bufp, int error, int xfer_len)
+{
+	struct scfg *cfg;
+	uint8_t *buf = *bufp;
+
+	cfg = enc->enc_private;
+	if (cfg == NULL)
+		return (ENXIO);
+	if (error != 0)
+		return (error);
+	SAFT_BAIL(3, xfer_len);
+	cfg->flag1 = buf[1];
+	cfg->flag2 = buf[2];
+
+	cfg->adm_status = 0;
+	if (cfg->flag1 & SAFT_FLG1_GLOBFAIL)
+		cfg->adm_status |= SES_ENCSTAT_CRITICAL;
+	else if (cfg->flag1 & SAFT_FLG1_GLOBWARN)
+		cfg->adm_status |= SES_ENCSTAT_NONCRITICAL;
+
+	return (0);
+}
+
+static int
+safte_process_status(enc_softc_t *enc, struct enc_fsm_state *state,
+    union ccb *ccb, uint8_t **bufp, int error, int xfer_len)
+{
+	struct scfg *cfg;
+	uint8_t *buf = *bufp;
+	int oid, r, i, nitems;
+	uint16_t tempflags;
+	enc_cache_t *cache = &enc->enc_cache;
+
+	cfg = enc->enc_private;
+	if (cfg == NULL)
+		return (ENXIO);
+	if (error != 0)
+		return (error);
+
+	oid = r = 0;
+	cfg->enc_status = 0;
+
+	for (nitems = i = 0; i < cfg->Nfans; i++) {
+		SAFT_BAIL(r, xfer_len);
+		/*
+		 * 0 = Fan Operational
+		 * 1 = Fan is malfunctioning
+		 * 2 = Fan is not present
+		 * 0x80 = Unknown or Not Reportable Status
+		 */
+		cache->elm_map[oid].encstat[1] = 0;	/* resvd */
+		cache->elm_map[oid].encstat[2] = 0;	/* resvd */
+		if (cfg->flag1 & SAFT_FLG1_ENCFANFAIL)
+			cache->elm_map[oid].encstat[3] |= 0x40;
+		else
+			cache->elm_map[oid].encstat[3] &= ~0x40;
+		switch ((int)buf[r]) {
+		case 0:
+			nitems++;
+			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK;
+			if ((cache->elm_map[oid].encstat[3] & 0x37) == 0)
+				cache->elm_map[oid].encstat[3] |= 0x27;
+			break;
+
+		case 1:
+			cache->elm_map[oid].encstat[0] =
+			    SES_OBJSTAT_CRIT;
+			/*
+			 * FAIL and FAN STOPPED synthesized
+			 */
+			cache->elm_map[oid].encstat[3] |= 0x10;
+			cache->elm_map[oid].encstat[3] &= ~0x07;
+			/*
+			 * Enclosure marked with CRITICAL error
+			 * if only one fan or no thermometers,
+			 * else the NONCRITICAL error is set.
+			 */
+			if (cfg->Nfans == 1 || (cfg->Ntherm + cfg->Ntstats) == 0)
+				cfg->enc_status |= SES_ENCSTAT_CRITICAL;
+			else
+				cfg->enc_status |= SES_ENCSTAT_NONCRITICAL;
+			break;
+		case 2:
+			cache->elm_map[oid].encstat[0] =
+			    SES_OBJSTAT_NOTINSTALLED;
+			cache->elm_map[oid].encstat[3] |= 0x10;
+			cache->elm_map[oid].encstat[3] &= ~0x07;
+			/*
+			 * Enclosure marked with CRITICAL error
+			 * if only one fan or no thermometers,
+			 * else the NONCRITICAL error is set.
+			 */
+			if (cfg->Nfans == 1)
+				cfg->enc_status |= SES_ENCSTAT_CRITICAL;
+			else
+				cfg->enc_status |= SES_ENCSTAT_NONCRITICAL;
+			break;
+		case 0x80:
+			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_UNKNOWN;
+			cache->elm_map[oid].encstat[3] = 0;
+			cfg->enc_status |= SES_ENCSTAT_INFO;
+			break;
+		default:
+			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_UNSUPPORTED;
+			ENC_LOG(enc, "Unknown fan%d status 0x%x\n", i,
+			    buf[r] & 0xff);
+			break;
+		}
+		cache->elm_map[oid++].svalid = 1;
+		r++;
+	}
+
+	/*
+	 * No matter how you cut it, no cooling elements when there
+	 * should be some there is critical.
+	 */
+	if (cfg->Nfans && nitems == 0)
+		cfg->enc_status |= SES_ENCSTAT_CRITICAL;
+
+	for (i = 0; i < cfg->Npwr; i++) {
+		SAFT_BAIL(r, xfer_len);
+		cache->elm_map[oid].encstat[0] = SES_OBJSTAT_UNKNOWN;
+		cache->elm_map[oid].encstat[1] = 0;	/* resvd */
+		cache->elm_map[oid].encstat[2] = 0;	/* resvd */
+		cache->elm_map[oid].encstat[3] = 0x20;	/* requested on */
+		switch (buf[r]) {
+		case 0x00:	/* pws operational and on */
+			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK;
+			break;
+		case 0x01:	/* pws operational and off */
+			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK;
+			cache->elm_map[oid].encstat[3] = 0x10;
+			cfg->enc_status |= SES_ENCSTAT_INFO;
+			break;
+		case 0x10:	/* pws is malfunctioning and commanded on */
+			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_CRIT;
+			cache->elm_map[oid].encstat[3] = 0x61;
+			cfg->enc_status |= SES_ENCSTAT_NONCRITICAL;
+			break;
+
+		case 0x11:	/* pws is malfunctioning and commanded off */
+			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_NONCRIT;
+			cache->elm_map[oid].encstat[3] = 0x51;
+			cfg->enc_status |= SES_ENCSTAT_NONCRITICAL;
+			break;
+		case 0x20:	/* pws is not present */
+			cache->elm_map[oid].encstat[0] =
+			    SES_OBJSTAT_NOTINSTALLED;
+			cache->elm_map[oid].encstat[3] = 0;
+			cfg->enc_status |= SES_ENCSTAT_INFO;
+			break;
+		case 0x21:	/* pws is present */
+			/*
+			 * This is for enclosures that cannot tell whether the
+			 * device is on or malfunctioning, but know that it is
+			 * present. Just fall through.
+			 */
+			/* FALLTHROUGH */
+		case 0x80:	/* Unknown or Not Reportable Status */
+			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_UNKNOWN;
+			cache->elm_map[oid].encstat[3] = 0;
+			cfg->enc_status |= SES_ENCSTAT_INFO;
+			break;
+		default:
+			ENC_LOG(enc, "unknown power supply %d status (0x%x)\n",
+			    i, buf[r] & 0xff);
+			break;
+		}
+		enc->enc_cache.elm_map[oid++].svalid = 1;
+		r++;
+	}
+
+	/*
+	 * Copy Slot SCSI IDs
+	 */
+	for (i = 0; i < cfg->Nslots; i++) {
+		SAFT_BAIL(r, xfer_len);
+		if (cache->elm_map[cfg->slotoff + i].enctype == ELMTYP_DEVICE)
+			cache->elm_map[cfg->slotoff + i].encstat[1] = buf[r];
+		r++;
+	}
+
+	/*
+	 * We always have doorlock status, no matter what,
+	 * but we only save the status if we have one.
+	 */
+	SAFT_BAIL(r, xfer_len);
+	if (cfg->DoorLock) {
+		/*
+		 * 0 = Door Locked
+		 * 1 = Door Unlocked, or no Lock Installed
+		 * 0x80 = Unknown or Not Reportable Status
+		 */
+		cache->elm_map[oid].encstat[1] = 0;
+		cache->elm_map[oid].encstat[2] = 0;
+		switch (buf[r]) {
+		case 0:
+			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK;
+			cache->elm_map[oid].encstat[3] = 0;
+			break;
+		case 1:
+			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK;
+			cache->elm_map[oid].encstat[3] = 1;
+			break;
+		case 0x80:
+			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_UNKNOWN;
+			cache->elm_map[oid].encstat[3] = 0;
+			cfg->enc_status |= SES_ENCSTAT_INFO;
+			break;
+		default:
+			cache->elm_map[oid].encstat[0] =
+			    SES_OBJSTAT_UNSUPPORTED;
+			ENC_LOG(enc, "unknown lock status 0x%x\n",
+			    buf[r] & 0xff);
+			break;
+		}
+		cache->elm_map[oid++].svalid = 1;
+	}
+	r++;
+
+	/*
+	 * We always have speaker status, no matter what,
+	 * but we only save the status if we have one.
+	 */
+	SAFT_BAIL(r, xfer_len);
+	if (cfg->Nspkrs) {
+		cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK;
+		cache->elm_map[oid].encstat[1] = 0;
+		cache->elm_map[oid].encstat[2] = 0;
+		if (buf[r] == 0) {
+			cache->elm_map[oid].encstat[0] |= SESCTL_DISABLE;
+			cache->elm_map[oid].encstat[3] |= 0x40;
+		}
+		cache->elm_map[oid++].svalid = 1;
+	}
+	r++;
+
+	/*
+	 * Now, for "pseudo" thermometers, we have two bytes
+	 * of information in enclosure status- 16 bits. Actually,
+	 * the MSB is a single TEMP ALERT flag indicating whether
+	 * any other bits are set, but, thanks to fuzzy thinking,
+	 * in the SAF-TE spec, this can also be set even if no
+	 * other bits are set, thus making this really another
+	 * binary temperature sensor.
+	 */
+
+	SAFT_BAIL(r + cfg->Ntherm, xfer_len);
+	tempflags = buf[r + cfg->Ntherm];
+	SAFT_BAIL(r + cfg->Ntherm + 1, xfer_len);
+	tempflags |= (tempflags << 8) | buf[r + cfg->Ntherm + 1];
+
+	for (i = 0; i < cfg->Ntherm; i++) {
+		SAFT_BAIL(r, xfer_len);
+		/*
+		 * Status is a range from -10 to 245 deg Celsius,
+		 * which we need to normalize to -20 to -245 according
+		 * to the latest SCSI spec, which makes little
+		 * sense since this would overflow an 8bit value.
+		 * Well, still, the base normalization is -20,
+		 * not -10, so we have to adjust.
+		 *
+		 * So what's over and under temperature?
+		 * Hmm- we'll state that 'normal' operating
+		 * is 10 to 40 deg Celsius.
+		 */
+
+		/*
+		 * Actually.... All of the units that people out in the world
+		 * seem to have do not come even close to setting a value that
+		 * complies with this spec.
+		 *
+		 * The closest explanation I could find was in an
+		 * LSI-Logic manual, which seemed to indicate that
+		 * this value would be set by whatever the I2C code
+		 * would interpolate from the output of an LM75
+		 * temperature sensor.
+		 *
+		 * This means that it is impossible to use the actual
+		 * numeric value to predict anything. But we don't want
+		 * to lose the value. So, we'll propagate the *uncorrected*
+		 * value and set SES_OBJSTAT_NOTAVAIL. We'll depend on the
+		 * temperature flags for warnings.
+		 */
+		if (tempflags & (1 << i)) {
+			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_CRIT;
+			cfg->enc_status |= SES_ENCSTAT_CRITICAL;
+		} else
+			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK;
+		cache->elm_map[oid].encstat[1] = 0;
+		cache->elm_map[oid].encstat[2] = buf[r];
+		cache->elm_map[oid].encstat[3] = 0;
+		cache->elm_map[oid++].svalid = 1;
+		r++;
+	}
+
+	for (i = 0; i <= cfg->Ntstats; i++) {
+		cache->elm_map[oid].encstat[1] = 0;
+		if (tempflags & (1 <<
+		    ((i == cfg->Ntstats) ? 15 : (cfg->Ntherm + i)))) {
+			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_CRIT;
+			cache->elm_map[4].encstat[2] = 0xff;
+			/*
+			 * Set 'over temperature' failure.
+			 */
+			cache->elm_map[oid].encstat[3] = 8;
+			cfg->enc_status |= SES_ENCSTAT_CRITICAL;
+		} else {
+			/*
+			 * We used to say 'not available' and synthesize a
+			 * nominal 30 deg (C)- that was wrong. Actually,
+			 * Just say 'OK', and use the reserved value of
+			 * zero.
+			 */
+			if ((cfg->Ntherm + cfg->Ntstats) == 0)
+				cache->elm_map[oid].encstat[0] =
+				    SES_OBJSTAT_NOTAVAIL;
+			else
+				cache->elm_map[oid].encstat[0] =
+				    SES_OBJSTAT_OK;
+			cache->elm_map[oid].encstat[2] = 0;
+			cache->elm_map[oid].encstat[3] = 0;
+		}
+		cache->elm_map[oid++].svalid = 1;
+	}
+	r += 2;
+
+	cache->enc_status =
+	    cfg->enc_status | cfg->slot_status | cfg->adm_status;
+	return (0);
+}
+
+static int
+safte_process_slotstatus(enc_softc_t *enc, struct enc_fsm_state *state,
+    union ccb *ccb, uint8_t **bufp, int error, int xfer_len)
+{
+	struct scfg *cfg;
+	uint8_t *buf = *bufp;
+	enc_cache_t *cache = &enc->enc_cache;
+	int oid, r, i;
+
+	cfg = enc->enc_private;
+	if (cfg == NULL)
+		return (ENXIO);
+	if (error != 0)
+		return (error);
+	cfg->slot_status = 0;
+	oid = cfg->slotoff;
+	for (r = i = 0; i < cfg->Nslots; i++, r += 4) {
+		SAFT_BAIL(r+3, xfer_len);
+		if (cache->elm_map[oid].enctype == ELMTYP_ARRAY_DEV)
+			cache->elm_map[oid].encstat[1] = 0;
+		cache->elm_map[oid].encstat[2] &= SESCTL_RQSID;
+		cache->elm_map[oid].encstat[3] = 0;
+		if ((buf[r+3] & 0x01) == 0) {	/* no device */
+			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_NOTINSTALLED;
+		} else if (buf[r+0] & 0x02) {
+			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_CRIT;
+			cfg->slot_status |= SES_ENCSTAT_CRITICAL;
+		} else if (buf[r+0] & 0x40) {
+			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_NONCRIT;
+			cfg->slot_status |= SES_ENCSTAT_NONCRITICAL;
+		} else {
+			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK;
+		}
+		if (buf[r+3] & 0x2) {
+			if (buf[r+3] & 0x01)
+				cache->elm_map[oid].encstat[2] |= SESCTL_RQSRMV;
+			else
+				cache->elm_map[oid].encstat[2] |= SESCTL_RQSINS;
+		}
+		if ((buf[r+3] & 0x04) == 0)
+			cache->elm_map[oid].encstat[3] |= SESCTL_DEVOFF;
+		if (buf[r+0] & 0x02)
+			cache->elm_map[oid].encstat[3] |= SESCTL_RQSFLT;
+		if (buf[r+0] & 0x40)
+			cache->elm_map[oid].encstat[0] |= SESCTL_PRDFAIL;
+		if (cache->elm_map[oid].enctype == ELMTYP_ARRAY_DEV) {
+			if (buf[r+0] & 0x01)
+				cache->elm_map[oid].encstat[1] |= 0x80;
+			if (buf[r+0] & 0x04)
+				cache->elm_map[oid].encstat[1] |= 0x02;
+			if (buf[r+0] & 0x08)
+				cache->elm_map[oid].encstat[1] |= 0x04;
+			if (buf[r+0] & 0x10)
+				cache->elm_map[oid].encstat[1] |= 0x08;
+			if (buf[r+0] & 0x20)
+				cache->elm_map[oid].encstat[1] |= 0x10;
+			if (buf[r+1] & 0x01)
+				cache->elm_map[oid].encstat[1] |= 0x20;
+			if (buf[r+1] & 0x02)
+				cache->elm_map[oid].encstat[1] |= 0x01;
+		}
+		cache->elm_map[oid++].svalid = 1;
+	}
+
+	cache->enc_status =
+	    cfg->enc_status | cfg->slot_status | cfg->adm_status;
+	return (0);
+}
+
+static int
+safte_fill_control_request(enc_softc_t *enc, struct enc_fsm_state *state,
+		       union ccb *ccb, uint8_t *buf)
+{
+	struct scfg *cfg;
+	enc_element_t *ep, *ep1;
+	safte_control_request_t *req;
+	int i, idx, xfer_len;
+
+	cfg = enc->enc_private;
+	if (cfg == NULL)
+		return (ENXIO);
+
+	if (enc->enc_cache.nelms == 0) {
+		enc_update_request(enc, SAFTE_UPDATE_READCONFIG);
+		return (-1);
+	}
+
+	if (cfg->current_request == NULL) {
+		cfg->current_request = TAILQ_FIRST(&cfg->requests);
+		TAILQ_REMOVE(&cfg->requests, cfg->current_request, links);
+		cfg->current_request_stage = 0;
+		cfg->current_request_stages = 1;
+	}
+	req = cfg->current_request;
+
+	idx = (int)req->elm_idx;
+	if (req->elm_idx == SES_SETSTATUS_ENC_IDX) {
+		cfg->adm_status = req->elm_stat[0] & ALL_ENC_STAT;
+		cfg->flag1 &= ~(SAFT_FLG1_GLOBFAIL|SAFT_FLG1_GLOBWARN);
+		if (req->elm_stat[0] & (SES_ENCSTAT_CRITICAL|SES_ENCSTAT_UNRECOV))
+			cfg->flag1 |= SAFT_FLG1_GLOBFAIL;
+		else if (req->elm_stat[0] & SES_ENCSTAT_NONCRITICAL)
+			cfg->flag1 |= SAFT_FLG1_GLOBWARN;
+		buf[0] = SAFTE_WT_GLOBAL;
+		buf[1] = cfg->flag1;
+		buf[2] = cfg->flag2;
+		buf[3] = 0;
+		xfer_len = 16;
+	} else {
+		ep = &enc->enc_cache.elm_map[idx];
+
+		switch (ep->enctype) {
+		case ELMTYP_DEVICE:
+		case ELMTYP_ARRAY_DEV:
+			switch (cfg->current_request_stage) {
+			case 0:
+				ep->priv = 0;
+				if (req->elm_stat[0] & SESCTL_PRDFAIL)
+					ep->priv |= 0x40;
+				if (req->elm_stat[3] & SESCTL_RQSFLT)
+					ep->priv |= 0x02;
+				if (ep->enctype == ELMTYP_ARRAY_DEV) {
+					if (req->elm_stat[1] & 0x01)
+						ep->priv |= 0x200;
+					if (req->elm_stat[1] & 0x02)
+						ep->priv |= 0x04;
+					if (req->elm_stat[1] & 0x04)
+						ep->priv |= 0x08;
+					if (req->elm_stat[1] & 0x08)
+						ep->priv |= 0x10;
+					if (req->elm_stat[1] & 0x10)
+						ep->priv |= 0x20;
+					if (req->elm_stat[1] & 0x20)
+						ep->priv |= 0x100;
+					if (req->elm_stat[1] & 0x80)
+						ep->priv |= 0x01;
+				}
+				if (ep->priv == 0)
+					ep->priv |= 0x01;	/* no errors */
+
+				buf[0] = SAFTE_WT_DSTAT;
+				for (i = 0; i < cfg->Nslots; i++) {
+					ep1 = &enc->enc_cache.elm_map[cfg->slotoff + i];
+					buf[1 + (3 * i)] = ep1->priv;
+					buf[2 + (3 * i)] = ep1->priv >> 8;
+				}
+				xfer_len = cfg->Nslots * 3 + 1;
+#define DEVON(x)	(!(((x)[2] & SESCTL_RQSINS) |	\
+			   ((x)[2] & SESCTL_RQSRMV) |	\
+			   ((x)[3] & SESCTL_DEVOFF)))
+				if (DEVON(req->elm_stat) != DEVON(ep->encstat))
+					cfg->current_request_stages++;
+#define IDON(x)		(!!((x)[2] & SESCTL_RQSID))
+				if (IDON(req->elm_stat) != IDON(ep->encstat))
+					cfg->current_request_stages++;
+				break;
+			case 1:
+			case 2:
+				buf[0] = SAFTE_WT_SLTOP;
+				buf[1] = idx - cfg->slotoff;
+				if (cfg->current_request_stage == 1 &&
+				    DEVON(req->elm_stat) != DEVON(ep->encstat)) {
+					if (DEVON(req->elm_stat))
+						buf[2] = 0x01;
+					else
+						buf[2] = 0x02;
+				} else {
+					if (IDON(req->elm_stat))
+						buf[2] = 0x04;
+					else
+						buf[2] = 0x00;
+					ep->encstat[2] &= ~SESCTL_RQSID;
+					ep->encstat[2] |= req->elm_stat[2] &
+					    SESCTL_RQSID;
+				}
+				xfer_len = 64;
+				break;
+			default:
+				return (EINVAL);
+			}
+			break;
+		case ELMTYP_POWER:
+			cfg->current_request_stages = 2;
+			switch (cfg->current_request_stage) {
+			case 0:
+				if (req->elm_stat[3] & SESCTL_RQSTFAIL) {
+					cfg->flag1 |= SAFT_FLG1_ENCPWRFAIL;
+				} else {
+					cfg->flag1 &= ~SAFT_FLG1_ENCPWRFAIL;
+				}
+				buf[0] = SAFTE_WT_GLOBAL;
+				buf[1] = cfg->flag1;
+				buf[2] = cfg->flag2;
+				buf[3] = 0;
+				xfer_len = 16;
+				break;
+			case 1:
+				buf[0] = SAFTE_WT_ACTPWS;
+				buf[1] = idx - cfg->pwroff;
+				if (req->elm_stat[3] & SESCTL_RQSTON)
+					buf[2] = 0x01;
+				else
+					buf[2] = 0x00;
+				buf[3] = 0;
+				xfer_len = 16;
+			default:
+				return (EINVAL);
+			}
+			break;
+		case ELMTYP_FAN:
+			if ((req->elm_stat[3] & 0x7) != 0)
+				cfg->current_request_stages = 2;
+			switch (cfg->current_request_stage) {
+			case 0:
+				if (req->elm_stat[3] & SESCTL_RQSTFAIL)
+					cfg->flag1 |= SAFT_FLG1_ENCFANFAIL;
+				else
+					cfg->flag1 &= ~SAFT_FLG1_ENCFANFAIL;
+				buf[0] = SAFTE_WT_GLOBAL;
+				buf[1] = cfg->flag1;
+				buf[2] = cfg->flag2;
+				buf[3] = 0;
+				xfer_len = 16;
+				break;
+			case 1:
+				buf[0] = SAFTE_WT_FANSPD;
+				buf[1] = idx;
+				if (req->elm_stat[3] & SESCTL_RQSTON) {
+					if ((req->elm_stat[3] & 0x7) == 7)
+						buf[2] = 4;
+					else if ((req->elm_stat[3] & 0x7) >= 5)
+						buf[2] = 3;
+					else if ((req->elm_stat[3] & 0x7) >= 3)
+						buf[2] = 2;
+					else
+						buf[2] = 1;
+				} else
+					buf[2] = 0;
+				buf[3] = 0;
+				xfer_len = 16;
+				ep->encstat[3] = req->elm_stat[3] & 0x67;
+			default:
+				return (EINVAL);
+			}
+			break;
+		case ELMTYP_DOORLOCK:
+			if (req->elm_stat[3] & 0x1)
+				cfg->flag2 &= ~SAFT_FLG2_LOCKDOOR;
+			else
+				cfg->flag2 |= SAFT_FLG2_LOCKDOOR;
+			buf[0] = SAFTE_WT_GLOBAL;
+			buf[1] = cfg->flag1;
+			buf[2] = cfg->flag2;
+			buf[3] = 0;
+			xfer_len = 16;
+			break;
+		case ELMTYP_ALARM:
+			if ((req->elm_stat[0] & SESCTL_DISABLE) ||
+			    (req->elm_stat[3] & 0x40)) {
+				cfg->flag2 &= ~SAFT_FLG1_ALARM;
+			} else if ((req->elm_stat[3] & 0x0f) != 0) {
+				cfg->flag2 |= SAFT_FLG1_ALARM;
+			} else {
+				cfg->flag2 &= ~SAFT_FLG1_ALARM;
+			}
+			buf[0] = SAFTE_WT_GLOBAL;
+			buf[1] = cfg->flag1;
+			buf[2] = cfg->flag2;
+			buf[3] = 0;
+			xfer_len = 16;
+			ep->encstat[3] = req->elm_stat[3];
+			break;
+		default:
+			return (EINVAL);
+		}
+	}
+
+	if (enc->enc_type == ENC_SEMB_SAFT) {
+		semb_write_buffer(&ccb->ataio, /*retries*/5,
+				enc_done, MSG_SIMPLE_Q_TAG,
+				buf, xfer_len, state->timeout);
+	} else {
+		scsi_write_buffer(&ccb->csio, /*retries*/5,
+				enc_done, MSG_SIMPLE_Q_TAG, 1,
+				0, 0, buf, xfer_len,
+				SSD_FULL_SIZE, state->timeout);
+	}
+	return (0);
+}
+
+static int
+safte_process_control_request(enc_softc_t *enc, struct enc_fsm_state *state,
+    union ccb *ccb, uint8_t **bufp, int error, int xfer_len)
+{
+	struct scfg *cfg;
+	safte_control_request_t *req;
+	int idx, type;
+
+	cfg = enc->enc_private;
+	if (cfg == NULL)
+		return (ENXIO);
+
+	req = cfg->current_request;
+	if (req->result == 0)
+		req->result = error;
+	if (++cfg->current_request_stage >= cfg->current_request_stages) {
+		idx = req->elm_idx;
+		if (idx == SES_SETSTATUS_ENC_IDX)
+			type = -1;
+		else
+			type = enc->enc_cache.elm_map[idx].enctype;
+		if (type == ELMTYP_DEVICE || type == ELMTYP_ARRAY_DEV)
+			enc_update_request(enc, SAFTE_UPDATE_READSLOTSTATUS);
+		else
+			enc_update_request(enc, SAFTE_UPDATE_READENCSTATUS);
+		cfg->current_request = NULL;
+		wakeup(req);
+	} else {
+		enc_update_request(enc, SAFTE_PROCESS_CONTROL_REQS);
+	}
+	return (0);
+}
+
+static void
+safte_softc_invalidate(enc_softc_t *enc)
+{
+	struct scfg *cfg;
+
+	cfg = enc->enc_private;
+	safte_terminate_control_requests(&cfg->requests, ENXIO);
+}
+
+static void
+safte_softc_cleanup(enc_softc_t *enc)
+{
+
+	ENC_FREE_AND_NULL(enc->enc_cache.elm_map);
+	ENC_FREE_AND_NULL(enc->enc_private);
+	enc->enc_cache.nelms = 0;
+}
+
+static int
+safte_init_enc(enc_softc_t *enc)
+{
+	struct scfg *cfg;
+	int err;
+	static char cdb0[6] = { SEND_DIAGNOSTIC };
+
+	cfg = enc->enc_private;
+	if (cfg == NULL)
+		return (ENXIO);
+
+	err = enc_runcmd(enc, cdb0, 6, NULL, 0);
+	if (err) {
+		return (err);
+	}
+	DELAY(5000);
+	cfg->flag1 = 0;
+	cfg->flag2 = 0;
+	err = safte_set_enc_status(enc, 0, 1);
+	return (err);
+}
+
+static int
+safte_get_enc_status(enc_softc_t *enc, int slpflg)
+{
+
+	return (0);
+}
+
+static int
+safte_set_enc_status(enc_softc_t *enc, uint8_t encstat, int slpflag)
+{
+	struct scfg *cfg;
+	safte_control_request_t req;
+
+	cfg = enc->enc_private;
+	if (cfg == NULL)
+		return (ENXIO);
+
+	req.elm_idx = SES_SETSTATUS_ENC_IDX;
+	req.elm_stat[0] = encstat & 0xf;
+	req.result = 0;
+	
+	TAILQ_INSERT_TAIL(&cfg->requests, &req, links);
+	enc_update_request(enc, SAFTE_PROCESS_CONTROL_REQS);
+	cam_periph_sleep(enc->periph, &req, PUSER, "encstat", 0);
+
+	return (req.result);
+}
+
+static int
+safte_get_elm_status(enc_softc_t *enc, encioc_elm_status_t *elms, int slpflg)
+{
+	int i = (int)elms->elm_idx;
+
+	elms->cstat[0] = enc->enc_cache.elm_map[i].encstat[0];
+	elms->cstat[1] = enc->enc_cache.elm_map[i].encstat[1];
+	elms->cstat[2] = enc->enc_cache.elm_map[i].encstat[2];
+	elms->cstat[3] = enc->enc_cache.elm_map[i].encstat[3];
+	return (0);
+}
+
+static int
+safte_set_elm_status(enc_softc_t *enc, encioc_elm_status_t *elms, int slpflag)
+{
+	struct scfg *cfg;
+	safte_control_request_t req;
+
+	cfg = enc->enc_private;
+	if (cfg == NULL)
+		return (ENXIO);
+
+	/* If this is clear, we don't do diddly.  */
+	if ((elms->cstat[0] & SESCTL_CSEL) == 0)
+		return (0);
+
+	req.elm_idx = elms->elm_idx;
+	memcpy(&req.elm_stat, elms->cstat, sizeof(req.elm_stat));
+	req.result = 0;
+
+	TAILQ_INSERT_TAIL(&cfg->requests, &req, links);
+	enc_update_request(enc, SAFTE_PROCESS_CONTROL_REQS);
+	cam_periph_sleep(enc->periph, &req, PUSER, "encstat", 0);
+
+	return (req.result);
+}
+
+static void
+safte_poll_status(enc_softc_t *enc)
+{
+
+	enc_update_request(enc, SAFTE_UPDATE_READENCSTATUS);
+	enc_update_request(enc, SAFTE_UPDATE_READSLOTSTATUS);
+}
+
+static struct enc_vec safte_enc_vec =
+{
+	.softc_invalidate	= safte_softc_invalidate,
+	.softc_cleanup	= safte_softc_cleanup,
+	.init_enc	= safte_init_enc,
+	.get_enc_status	= safte_get_enc_status,
+	.set_enc_status	= safte_set_enc_status,
+	.get_elm_status	= safte_get_elm_status,
+	.set_elm_status	= safte_set_elm_status,
+	.poll_status	= safte_poll_status
+};
+
+int
+safte_softc_init(enc_softc_t *enc)
+{
+	struct scfg *cfg;
+
+	enc->enc_vec = safte_enc_vec;
+	enc->enc_fsm_states = enc_fsm_states;
+
+	if (enc->enc_private == NULL) {
+		enc->enc_private = ENC_MALLOCZ(SAFT_PRIVATE);
+		if (enc->enc_private == NULL)
+			return (ENOMEM);
+	}
+	cfg = enc->enc_private;
+
+	enc->enc_cache.nelms = 0;
+	enc->enc_cache.enc_status = 0;
+
+	TAILQ_INIT(&cfg->requests);
+	return (0);
+}
+
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/scsi/scsi_enc_ses.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/cam/scsi/scsi_enc_ses.c	Wed Jul 25 16:45:04 2012 +0300
@@ -0,0 +1,2816 @@
+/*-
+ * Copyright (c) 2000 Matthew Jacob
+ * Copyright (c) 2010 Spectra Logic Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/**
+ * \file scsi_enc_ses.c
+ *
+ * Structures and routines specific && private to SES only
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_enc_ses.c 238739 2012-07-24 13:08:43Z mav $");
+
+#include <sys/param.h>
+
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/sbuf.h>
+#include <sys/sx.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_xpt_periph.h>
+#include <cam/cam_periph.h>
+
+#include <cam/scsi/scsi_message.h>
+#include <cam/scsi/scsi_enc.h>
+#include <cam/scsi/scsi_enc_internal.h>
+
+#include <opt_enc.h>
+
+/* SES Native Type Device Support */
+
+/* SES Diagnostic Page Codes */
+typedef enum {
+	SesSupportedPages	= 0x0,
+	SesConfigPage		= 0x1,
+	SesControlPage		= 0x2,
+	SesStatusPage		= SesControlPage,
+	SesHelpTxt		= 0x3,
+	SesStringOut		= 0x4,
+	SesStringIn		= SesStringOut,
+	SesThresholdOut		= 0x5,
+	SesThresholdIn		= SesThresholdOut,
+	SesArrayControl		= 0x6,	/* Obsolete in SES v2 */
+	SesArrayStatus		= SesArrayControl,
+	SesElementDescriptor	= 0x7,
+	SesShortStatus		= 0x8,
+	SesEnclosureBusy	= 0x9,
+	SesAddlElementStatus	= 0xa
+} SesDiagPageCodes;
+
+typedef struct ses_type {
+	const struct ses_elm_type_desc  *hdr;
+	const char			*text;
+} ses_type_t;
+
+typedef struct ses_comstat {
+	uint8_t	comstatus;
+	uint8_t	comstat[3];
+} ses_comstat_t;
+
+typedef union ses_addl_data {
+	struct ses_elm_sas_device_phy *sasdev_phys;
+	struct ses_elm_sas_expander_phy *sasexp_phys;
+	struct ses_elm_sas_port_phy *sasport_phys;
+	struct ses_fcobj_port *fc_ports;
+} ses_add_data_t;
+
+typedef struct ses_addl_status {
+	struct ses_elm_addlstatus_base_hdr *hdr;
+	union {
+		union ses_fcobj_hdr *fc;
+		union ses_elm_sas_hdr *sas;
+	} proto_hdr;
+	union ses_addl_data proto_data;	/* array sizes stored in header */
+} ses_add_status_t;
+
+typedef struct ses_element {
+	uint8_t eip;			/* eip bit is set */
+	uint16_t descr_len;		/* length of the descriptor */
+	char *descr;			/* descriptor for this object */
+	struct ses_addl_status addl;	/* additional status info */
+} ses_element_t;
+
+typedef struct ses_control_request {
+	int	      elm_idx;
+	ses_comstat_t elm_stat;
+	int	      result;
+	TAILQ_ENTRY(ses_control_request) links;
+} ses_control_request_t;
+TAILQ_HEAD(ses_control_reqlist, ses_control_request);
+typedef struct ses_control_reqlist ses_control_reqlist_t;
+enum {
+	SES_SETSTATUS_ENC_IDX = -1
+};
+
+static void
+ses_terminate_control_requests(ses_control_reqlist_t *reqlist, int result)
+{
+	ses_control_request_t *req;
+
+	while ((req = TAILQ_FIRST(reqlist)) != NULL) {
+		TAILQ_REMOVE(reqlist, req, links);
+		req->result = result;
+		wakeup(req);
+	}
+}
+
+enum ses_iter_index_values {
+	/**
+	 * \brief  Value of an initialized but invalid index
+	 *         in a ses_iterator object.
+	 *
+	 * This value is used for the  individual_element_index of
+	 * overal status elements and for all index types when
+	 * an iterator is first initialized.
+	 */
+	ITERATOR_INDEX_INVALID = -1,
+
+	/**
+	 * \brief  Value of an index in a ses_iterator object
+	 *	   when the iterator has traversed past the last
+	 *	   valid element..
+	 */
+	ITERATOR_INDEX_END     = INT_MAX
+};
+
+/**
+ * \brief Structure encapsulating all data necessary to traverse the
+ *        elements of a SES configuration.
+ *
+ * The ses_iterator object simplifies the task of iterating through all
+ * elements detected via the SES configuration page by tracking the numerous
+ * element indexes that, instead of memoizing in the softc, we calculate
+ * on the fly during the traversal of the element objects.  The various
+ * indexes are necessary due to the varying needs of matching objects in
+ * the different SES pages.  Some pages (e.g. Status/Control) contain all
+ * elements, while others (e.g. Additional Element Status) only contain
+ * individual elements (no overal status elements) of particular types.
+ *
+ * To use an iterator, initialize it with ses_iter_init(), and then
+ * use ses_iter_next() to traverse the elements (including the first) in
+ * the configuration.  Once an iterator is initiailized with ses_iter_init(),
+ * you may also seek to any particular element by either it's global or
+ * individual element index via the ses_iter_seek_to() function.  You may
+ * also return an iterator to the position just before the first element
+ * (i.e. the same state as after an ses_iter_init()), with ses_iter_reset().
+ */
+struct ses_iterator {
+	/**
+	 * \brief Backlink to the overal software configuration structure.
+	 *
+	 * This is included for convenience so the iteration functions
+	 * need only take a single, struct ses_iterator *, argument.
+	 */
+	enc_softc_t *enc;
+
+	enc_cache_t *cache;
+
+	/**
+	 * \brief Index of the type of the current element within the
+	 *        ses_cache's ses_types array.
+	 */
+	int	          type_index;
+
+	/**
+	 * \brief The position (0 based) of this element relative to all other
+	 *        elements of this type.
+	 *
+	 * This index resets to zero every time the iterator transitions
+	 * to elements of a new type in the configuration.
+	 */
+	int	          type_element_index;
+
+	/**
+	 * \brief The position (0 based) of this element relative to all
+	 *        other individual status elements in the configuration.
+	 *
+	 * This index ranges from 0 through the number of individual
+	 * elements in the configuration.  When the iterator returns
+	 * an overall status element, individual_element_index is
+	 * set to ITERATOR_INDEX_INVALID, to indicate that it does
+	 * not apply to the current element.
+	 */
+	int	          individual_element_index;
+
+	/**
+	 * \brief The position (0 based) of this element relative to
+	 *        all elements in the configration.
+	 *
+	 * This index is appropriate for indexing into enc->ses_elm_map.
+	 */
+	int	          global_element_index;
+
+	/**
+	 * \brief The last valid individual element index of this
+	 *        iterator.
+	 *
+	 * When an iterator traverses an overal status element, the
+	 * individual element index is reset to ITERATOR_INDEX_INVALID
+	 * to prevent unintential use of the individual_element_index
+	 * field.  The saved_individual_element_index allows the iterator
+	 * to restore it's position in the individual elements upon
+	 * reaching the next individual element.
+	 */
+	int	          saved_individual_element_index;
+};
+
+typedef enum {
+	SES_UPDATE_NONE,
+	SES_UPDATE_PAGES,
+	SES_UPDATE_GETCONFIG,
+	SES_UPDATE_GETSTATUS,
+	SES_UPDATE_GETELMDESCS,
+	SES_UPDATE_GETELMADDLSTATUS,
+	SES_PROCESS_CONTROL_REQS,
+	SES_PUBLISH_PHYSPATHS,
+	SES_PUBLISH_CACHE,
+	SES_NUM_UPDATE_STATES
+} ses_update_action;
+
+static enc_softc_cleanup_t ses_softc_cleanup;
+
+#define	SCSZ	0x8000
+
+static fsm_fill_handler_t ses_fill_rcv_diag_io;
+static fsm_fill_handler_t ses_fill_control_request;
+static fsm_done_handler_t ses_process_pages;
+static fsm_done_handler_t ses_process_config;
+static fsm_done_handler_t ses_process_status;
+static fsm_done_handler_t ses_process_elm_descs;
+static fsm_done_handler_t ses_process_elm_addlstatus;
+static fsm_done_handler_t ses_process_control_request;
+static fsm_done_handler_t ses_publish_physpaths;
+static fsm_done_handler_t ses_publish_cache;
+
+static struct enc_fsm_state enc_fsm_states[SES_NUM_UPDATE_STATES] =
+{
+	{ "SES_UPDATE_NONE", 0, 0, 0, NULL, NULL, NULL },
+	{
+		"SES_UPDATE_PAGES",
+		SesSupportedPages,
+		SCSZ,
+		60 * 1000,
+		ses_fill_rcv_diag_io,
+		ses_process_pages,
+		enc_error
+	},
+	{
+		"SES_UPDATE_GETCONFIG",
+		SesConfigPage,
+		SCSZ,
+		60 * 1000,
+		ses_fill_rcv_diag_io,
+		ses_process_config,
+		enc_error
+	},
+	{
+		"SES_UPDATE_GETSTATUS",
+		SesStatusPage,
+		SCSZ,
+		60 * 1000,
+		ses_fill_rcv_diag_io,
+		ses_process_status,
+		enc_error
+	},
+	{
+		"SES_UPDATE_GETELMDESCS",
+		SesElementDescriptor,
+		SCSZ,
+		60 * 1000,
+		ses_fill_rcv_diag_io,
+		ses_process_elm_descs,
+		enc_error
+	},
+	{
+		"SES_UPDATE_GETELMADDLSTATUS",
+		SesAddlElementStatus,
+		SCSZ,
+		60 * 1000,
+		ses_fill_rcv_diag_io,
+		ses_process_elm_addlstatus,
+		enc_error
+	},
+	{
+		"SES_PROCESS_CONTROL_REQS",
+		SesControlPage,
+		SCSZ,
+		60 * 1000,
+		ses_fill_control_request,
+		ses_process_control_request,
+		enc_error
+	},
+	{
+		"SES_PUBLISH_PHYSPATHS",
+		0,
+		0,
+		0,
+		NULL,
+		ses_publish_physpaths,
+		NULL
+	},
+	{
+		"SES_PUBLISH_CACHE",
+		0,
+		0,
+		0,
+		NULL,
+		ses_publish_cache,
+		NULL
+	}
+};
+
+typedef struct ses_cache {
+	/* Source for all the configuration data pointers */
+	const struct ses_cfg_page		*cfg_page;
+
+	/* References into the config page. */
+	const struct ses_enc_desc * const	*subencs;
+	uint8_t					 ses_ntypes;
+	const ses_type_t			*ses_types;
+
+	/* Source for all the status pointers */
+	const struct ses_status_page		*status_page;
+
+	/* Source for all the object descriptor pointers */
+	const struct ses_elem_descr_page	*elm_descs_page;
+
+	/* Source for all the additional object status pointers */
+	const struct ses_addl_elem_status_page  *elm_addlstatus_page;
+
+} ses_cache_t;
+
+typedef struct ses_softc {
+	uint32_t		ses_flags;
+#define	SES_FLAG_TIMEDCOMP	0x01
+#define	SES_FLAG_ADDLSTATUS	0x02
+
+	ses_control_reqlist_t	ses_requests;
+	ses_control_reqlist_t	ses_pending_requests;
+} ses_softc_t;
+
+/**
+ * \brief Reset a SES iterator to just before the first element
+ *        in the configuration.
+ *
+ * \param iter  The iterator object to reset.
+ *
+ * The indexes within a reset iterator are invalid and will only
+ * become valid upon completion of a ses_iter_seek_to() or a
+ * ses_iter_next().
+ */
+static void
+ses_iter_reset(struct ses_iterator *iter)
+{
+	/*
+	 * Set our indexes to just before the first valid element
+	 * of the first type (ITERATOR_INDEX_INVALID == -1).  This
+	 * simplifies the implementation of ses_iter_next().
+	 */
+	iter->type_index                     = 0;
+	iter->type_element_index             = ITERATOR_INDEX_INVALID;
+	iter->global_element_index           = ITERATOR_INDEX_INVALID;
+	iter->individual_element_index       = ITERATOR_INDEX_INVALID;
+	iter->saved_individual_element_index = ITERATOR_INDEX_INVALID;
+}
+
+/**
+ * \brief Initialize the storage of a SES iterator and reset it to
+ *        the position just before the first element of the
+ *        configuration.
+ *
+ * \param enc	The SES softc for the SES instance whose configuration
+ *              will be enumerated by this iterator.
+ * \param iter  The iterator object to initialize.
+ */
+static void
+ses_iter_init(enc_softc_t *enc, enc_cache_t *cache, struct ses_iterator *iter)
+{
+	iter->enc = enc;
+	iter->cache = cache;
+	ses_iter_reset(iter);
+}
+
+/**
+ * \brief Traverse the provided SES iterator to the next element
+ *        within the configuraiton.
+ *
+ * \param iter  The iterator to move.
+ *
+ * \return  If a valid next element exists, a pointer to it's enc_element_t.
+ *          Otherwise NULL.
+ */
+static enc_element_t *
+ses_iter_next(struct ses_iterator *iter)
+{
+	ses_cache_t	 *ses_cache;
+	const ses_type_t *element_type;
+
+	ses_cache = iter->cache->private;
+
+	/*
+	 * Note: Treat nelms as signed, so we will hit this case
+	 *       and immediately terminate the iteration if the
+	 *	 configuration has 0 objects.
+	 */
+	if (iter->global_element_index >= (int)iter->cache->nelms - 1) {
+
+		/* Elements exhausted. */
+		iter->type_index	       = ITERATOR_INDEX_END;
+		iter->type_element_index       = ITERATOR_INDEX_END;
+		iter->global_element_index     = ITERATOR_INDEX_END;
+		iter->individual_element_index = ITERATOR_INDEX_END;
+		return (NULL);
+	}
+
+	KASSERT((iter->type_index < ses_cache->ses_ntypes),
+		("Corrupted element iterator. %d not less than %d",
+		 iter->type_index, ses_cache->ses_ntypes));
+
+	element_type = &ses_cache->ses_types[iter->type_index];
+	iter->global_element_index++;
+	iter->type_element_index++;
+
+	/*
+	 * There is an object for overal type status in addition
+	 * to one for each allowed element, but only if the element
+	 * count is non-zero.
+	 */
+	if (iter->type_element_index > element_type->hdr->etype_maxelt) {
+
+		/*
+		 * We've exhausted the elements of this type.
+		 * This next element belongs to the next type.
+		 */
+		iter->type_index++;
+		iter->type_element_index = 0;
+		iter->saved_individual_element_index
+		    = iter->individual_element_index;
+		iter->individual_element_index = ITERATOR_INDEX_INVALID;
+	}
+
+	if (iter->type_element_index > 0) {
+		if (iter->type_element_index == 1) {
+			iter->individual_element_index
+			    = iter->saved_individual_element_index;
+		}
+		iter->individual_element_index++;
+	}
+
+	return (&iter->cache->elm_map[iter->global_element_index]);
+}
+
+/**
+ * Element index types tracked by a SES iterator.
+ */
+typedef enum {
+	/**
+	 * Index relative to all elements (overall and individual)
+	 * in the system.
+	 */
+	SES_ELEM_INDEX_GLOBAL,
+
+	/**
+	 * \brief Index relative to all individual elements in the system.
+	 *
+	 * This index counts only individual elements, skipping overall
+	 * status elements.  This is the index space of the additional
+	 * element status page (page 0xa).
+	 */
+	SES_ELEM_INDEX_INDIVIDUAL
+} ses_elem_index_type_t;
+
+/**
+ * \brief Move the provided iterator forwards or backwards to the object 
+ *        having the give index.
+ *
+ * \param iter           The iterator on which to perform the seek.
+ * \param element_index  The index of the element to find.
+ * \param index_type     The type (global or individual) of element_index.
+ *
+ * \return  If the element is found, a pointer to it's enc_element_t.
+ *          Otherwise NULL.
+ */
+static enc_element_t *
+ses_iter_seek_to(struct ses_iterator *iter, int element_index,
+		 ses_elem_index_type_t index_type)
+{
+	enc_element_t	*element;
+	int		*cur_index;
+
+	if (index_type == SES_ELEM_INDEX_GLOBAL)
+		cur_index = &iter->global_element_index;
+	else
+		cur_index = &iter->individual_element_index;
+
+	if (*cur_index == element_index) {
+		/* Already there. */
+		return (&iter->cache->elm_map[iter->global_element_index]);
+	}
+
+	ses_iter_reset(iter);
+	while ((element = ses_iter_next(iter)) != NULL
+	    && *cur_index != element_index)
+		;
+
+	if (*cur_index != element_index)
+		return (NULL);
+
+	return (element);
+}
+
+#if 0
+static int ses_encode(enc_softc_t *, uint8_t *, int, int,
+    struct ses_comstat *);
+#endif
+static int ses_set_timed_completion(enc_softc_t *, uint8_t);
+#if 0
+static int ses_putstatus(enc_softc_t *, int, struct ses_comstat *);
+#endif
+
+static void ses_print_addl_data(enc_softc_t *, enc_element_t *);
+
+/*=========================== SES cleanup routines ===========================*/
+
+static void
+ses_cache_free_elm_addlstatus(enc_softc_t *enc, enc_cache_t *cache)
+{
+	ses_cache_t   *ses_cache;
+	ses_cache_t   *other_ses_cache;
+	enc_element_t *cur_elm;
+	enc_element_t *last_elm;
+
+	ENC_DLOG(enc, "%s: enter\n", __func__);
+	ses_cache = cache->private;
+	if (ses_cache->elm_addlstatus_page == NULL)
+		return;
+
+	for (cur_elm = cache->elm_map,
+	     last_elm = &cache->elm_map[cache->nelms - 1];
+	     cur_elm <= last_elm; cur_elm++) {
+		ses_element_t *elmpriv;
+
+		elmpriv = cur_elm->elm_private;
+
+		/* Clear references to the additional status page. */
+		bzero(&elmpriv->addl, sizeof(elmpriv->addl));
+	}
+
+	other_ses_cache = enc_other_cache(enc, cache)->private;
+	if (other_ses_cache->elm_addlstatus_page
+	 != ses_cache->elm_addlstatus_page)
+		ENC_FREE(ses_cache->elm_addlstatus_page);
+	ses_cache->elm_addlstatus_page = NULL;
+}
+
+static void
+ses_cache_free_elm_descs(enc_softc_t *enc, enc_cache_t *cache)
+{
+	ses_cache_t   *ses_cache;
+	ses_cache_t   *other_ses_cache;
+	enc_element_t *cur_elm;
+	enc_element_t *last_elm;
+
+	ENC_DLOG(enc, "%s: enter\n", __func__);
+	ses_cache = cache->private;
+	if (ses_cache->elm_descs_page == NULL)
+		return;
+
+	for (cur_elm = cache->elm_map,
+	     last_elm = &cache->elm_map[cache->nelms - 1];
+	     cur_elm <= last_elm; cur_elm++) {
+		ses_element_t *elmpriv;
+
+		elmpriv = cur_elm->elm_private;
+		elmpriv->descr_len = 0;
+		elmpriv->descr = NULL;
+	}
+
+	other_ses_cache = enc_other_cache(enc, cache)->private;
+	if (other_ses_cache->elm_descs_page
+	 != ses_cache->elm_descs_page)
+		ENC_FREE(ses_cache->elm_descs_page);
+	ses_cache->elm_descs_page = NULL;
+}
+
+static void
+ses_cache_free_status(enc_softc_t *enc, enc_cache_t *cache)
+{
+	ses_cache_t *ses_cache;
+	ses_cache_t *other_ses_cache;
+
+	ENC_DLOG(enc, "%s: enter\n", __func__);
+	ses_cache   = cache->private;
+	if (ses_cache->status_page == NULL)
+		return;
+	
+	other_ses_cache = enc_other_cache(enc, cache)->private;
+	if (other_ses_cache->status_page != ses_cache->status_page)
+		ENC_FREE(ses_cache->status_page);
+	ses_cache->status_page = NULL;
+}
+
+static void
+ses_cache_free_elm_map(enc_softc_t *enc, enc_cache_t *cache)
+{
+	enc_element_t *cur_elm;
+	enc_element_t *last_elm;
+
+	ENC_DLOG(enc, "%s: enter\n", __func__);
+	if (cache->elm_map == NULL)
+		return;
+
+	ses_cache_free_elm_descs(enc, cache);
+	ses_cache_free_elm_addlstatus(enc, cache);
+	for (cur_elm = cache->elm_map,
+	     last_elm = &cache->elm_map[cache->nelms - 1];
+	     cur_elm <= last_elm; cur_elm++) {
+
+		ENC_FREE_AND_NULL(cur_elm->elm_private);
+	}
+	ENC_FREE_AND_NULL(cache->elm_map);
+	cache->nelms = 0;
+	ENC_DLOG(enc, "%s: exit\n", __func__);
+}
+
+static void
+ses_cache_free(enc_softc_t *enc, enc_cache_t *cache)
+{
+	ses_cache_t *other_ses_cache;
+	ses_cache_t *ses_cache;
+
+	ENC_DLOG(enc, "%s: enter\n", __func__);
+	ses_cache_free_elm_addlstatus(enc, cache);
+	ses_cache_free_status(enc, cache);
+	ses_cache_free_elm_map(enc, cache);
+
+	ses_cache = cache->private;
+	ses_cache->ses_ntypes = 0;
+
+	other_ses_cache = enc_other_cache(enc, cache)->private;
+	if (other_ses_cache->subencs != ses_cache->subencs)
+		ENC_FREE(ses_cache->subencs);
+	ses_cache->subencs = NULL;
+
+	if (other_ses_cache->ses_types != ses_cache->ses_types)
+		ENC_FREE(ses_cache->ses_types);
+	ses_cache->ses_types = NULL;
+
+	if (other_ses_cache->cfg_page != ses_cache->cfg_page)
+		ENC_FREE(ses_cache->cfg_page);
+	ses_cache->cfg_page = NULL;
+
+	ENC_DLOG(enc, "%s: exit\n", __func__);
+}
+
+static void
+ses_cache_clone(enc_softc_t *enc, enc_cache_t *src, enc_cache_t *dst)
+{
+	ses_cache_t   *dst_ses_cache;
+	ses_cache_t   *src_ses_cache;
+	enc_element_t *src_elm;
+	enc_element_t *dst_elm;
+	enc_element_t *last_elm;
+
+	ses_cache_free(enc, dst);
+	src_ses_cache = src->private;
+	dst_ses_cache = dst->private;
+
+	/*
+	 * The cloned enclosure cache and ses specific cache are
+	 * mostly identical to the source.
+	 */
+	*dst = *src;
+	*dst_ses_cache = *src_ses_cache;
+
+	/*
+	 * But the ses cache storage is still independent.  Restore
+	 * the pointer that was clobbered by the structure copy above.
+	 */
+	dst->private = dst_ses_cache;
+
+	/*
+	 * The element map is independent even though it starts out
+	 * pointing to the same constant page data.
+	 */
+	dst->elm_map = ENC_MALLOCZ(dst->nelms * sizeof(enc_element_t));
+	memcpy(dst->elm_map, src->elm_map, dst->nelms * sizeof(enc_element_t));
+	for (dst_elm = dst->elm_map, src_elm = src->elm_map,
+	     last_elm = &src->elm_map[src->nelms - 1];
+	     src_elm <= last_elm; src_elm++, dst_elm++) {
+
+		dst_elm->elm_private = ENC_MALLOCZ(sizeof(ses_element_t));
+		memcpy(dst_elm->elm_private, src_elm->elm_private,
+		       sizeof(ses_element_t));
+	}
+}
+
+/* Structure accessors.  These are strongly typed to avoid errors. */
+
+int
+ses_elm_sas_descr_type(union ses_elm_sas_hdr *obj)
+{
+	return ((obj)->base_hdr.byte1 >> 6);
+}
+int
+ses_elm_addlstatus_proto(struct ses_elm_addlstatus_base_hdr *hdr)
+{
+	return ((hdr)->byte0 & 0xf);
+}
+int
+ses_elm_addlstatus_eip(struct ses_elm_addlstatus_base_hdr *hdr)
+{
+	return ((hdr)->byte0 >> 4) & 0x1;
+}
+int
+ses_elm_addlstatus_invalid(struct ses_elm_addlstatus_base_hdr *hdr)
+{
+	return ((hdr)->byte0 >> 7);
+}
+int
+ses_elm_sas_type0_not_all_phys(union ses_elm_sas_hdr *hdr)
+{
+	return ((hdr)->type0_noneip.byte1 & 0x1);
+}
+int
+ses_elm_sas_dev_phy_sata_dev(struct ses_elm_sas_device_phy *phy)
+{
+	return ((phy)->target_ports & 0x1);
+}
+int
+ses_elm_sas_dev_phy_sata_port(struct ses_elm_sas_device_phy *phy)
+{
+	return ((phy)->target_ports >> 7);
+}
+int
+ses_elm_sas_dev_phy_dev_type(struct ses_elm_sas_device_phy *phy)
+{
+	return (((phy)->byte0 >> 4) & 0x7);
+}
+
+/**
+ * \brief Verify that the cached configuration data in our softc
+ *        is valid for processing the page data corresponding to
+ *        the provided page header.
+ *
+ * \param ses_cache The SES cache to validate.
+ * \param gen_code  The 4 byte generation code from a SES diagnostic
+ *		    page header.
+ *
+ * \return  non-zero if true, 0 if false.
+ */
+static int
+ses_config_cache_valid(ses_cache_t *ses_cache, const uint8_t *gen_code)
+{
+	uint32_t cache_gc;
+	uint32_t cur_gc;
+
+	if (ses_cache->cfg_page == NULL)
+		return (0);
+
+	cache_gc = scsi_4btoul(ses_cache->cfg_page->hdr.gen_code);
+	cur_gc   = scsi_4btoul(gen_code);
+	return (cache_gc == cur_gc);
+}
+
+/**
+ * Function signature for consumers of the ses_devids_iter() interface.
+ */
+typedef void ses_devid_callback_t(enc_softc_t *, enc_element_t *,
+				  struct scsi_vpd_id_descriptor *, void *);
+
+/**
+ * \brief Iterate over and create vpd device id records from the
+ *        additional element status data for elm, passing that data
+ *        to the provided callback.
+ *
+ * \param enc	        SES instance containing elm
+ * \param elm	        Element for which to extract device ID data.
+ * \param callback      The callback function to invoke on each generated
+ *                      device id descriptor for elm.
+ * \param callback_arg  Argument passed through to callback on each invocation.
+ */
+static void
+ses_devids_iter(enc_softc_t *enc, enc_element_t *elm,
+		ses_devid_callback_t *callback, void *callback_arg)
+{
+	ses_element_t           *elmpriv;
+	struct ses_addl_status *addl;
+	u_int                   i;
+	size_t			devid_record_size;
+
+	elmpriv = elm->elm_private;
+	addl = &(elmpriv->addl);
+
+	/*
+	 * Don't assume this object has additional status information, or
+	 * that it is a SAS device, or that it is a device slot device.
+	 */
+	if (addl->hdr == NULL || addl->proto_hdr.sas == NULL
+	 || addl->proto_data.sasdev_phys == NULL)
+		return;
+
+	devid_record_size = SVPD_DEVICE_ID_DESC_HDR_LEN
+			  + sizeof(struct scsi_vpd_id_naa_ieee_reg);
+	for (i = 0; i < addl->proto_hdr.sas->base_hdr.num_phys; i++) {
+		uint8_t			       devid_buf[devid_record_size];
+		struct scsi_vpd_id_descriptor *devid;
+		uint8_t			      *phy_addr;
+
+		devid = (struct scsi_vpd_id_descriptor *)devid_buf;
+		phy_addr = addl->proto_data.sasdev_phys[i].phy_addr;
+		devid->proto_codeset = (SCSI_PROTO_SAS << SVPD_ID_PROTO_SHIFT)
+				     | SVPD_ID_CODESET_BINARY;
+		devid->id_type       = SVPD_ID_PIV
+				     | SVPD_ID_ASSOC_PORT
+				     | SVPD_ID_TYPE_NAA;
+		devid->reserved	     = 0;
+		devid->length	     = sizeof(struct scsi_vpd_id_naa_ieee_reg);
+		memcpy(devid->identifier, phy_addr, devid->length);
+
+		callback(enc, elm, devid, callback_arg);
+	}
+}
+
+/**
+ * Function signature for consumers of the ses_paths_iter() interface.
+ */
+typedef void ses_path_callback_t(enc_softc_t *, enc_element_t *,
+				 struct cam_path *, void *);
+
+/**
+ * Argument package passed through ses_devids_iter() by
+ * ses_paths_iter() to ses_path_iter_devid_callback().
+ */
+typedef struct ses_path_iter_args {
+	ses_path_callback_t *callback;
+	void		    *callback_arg;
+} ses_path_iter_args_t;
+
+/**
+ * ses_devids_iter() callback function used by ses_paths_iter()
+ * to map device ids to peripheral driver instances.
+ *
+ * \param enc	  SES instance containing elm
+ * \param elm	  Element on which device ID matching is active.
+ * \param periph  A device ID corresponding to elm.
+ * \param arg     Argument passed through to callback on each invocation.
+ */
+static void
+ses_path_iter_devid_callback(enc_softc_t *enc, enc_element_t *elem,
+			       struct scsi_vpd_id_descriptor *devid,
+			       void *arg)
+{
+	struct ccb_dev_match         cdm;
+	struct dev_match_pattern     match_pattern;
+	struct dev_match_result      match_result;
+	struct device_match_result  *device_match;
+	struct device_match_pattern *device_pattern;
+	ses_path_iter_args_t	    *args;
+
+	args = (ses_path_iter_args_t *)arg;
+	match_pattern.type = DEV_MATCH_DEVICE;
+	device_pattern = &match_pattern.pattern.device_pattern;
+	device_pattern->flags = DEV_MATCH_DEVID;
+	device_pattern->data.devid_pat.id_len = 
+	    offsetof(struct scsi_vpd_id_descriptor, identifier)
+	  + devid->length;
+	memcpy(device_pattern->data.devid_pat.id, devid,
+	       device_pattern->data.devid_pat.id_len);
+
+	memset(&cdm, 0, sizeof(cdm));
+	if (xpt_create_path(&cdm.ccb_h.path, /*periph*/NULL, CAM_XPT_PATH_ID,
+			    CAM_TARGET_WILDCARD,
+			    CAM_LUN_WILDCARD) != CAM_REQ_CMP)
+		return;
+
+	cdm.ccb_h.func_code = XPT_DEV_MATCH;
+	cdm.num_patterns    = 1;
+	cdm.patterns        = &match_pattern;
+	cdm.pattern_buf_len = sizeof(match_pattern);
+	cdm.match_buf_len   = sizeof(match_result);
+	cdm.matches         = &match_result;
+
+	xpt_action((union ccb *)&cdm);
+	xpt_free_path(cdm.ccb_h.path);
+
+	if ((cdm.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP
+	 || (cdm.status != CAM_DEV_MATCH_LAST
+	  && cdm.status != CAM_DEV_MATCH_MORE)
+	 || cdm.num_matches == 0)
+		return;
+
+	device_match = &match_result.result.device_result;
+	if (xpt_create_path(&cdm.ccb_h.path, /*periph*/NULL,
+			    device_match->path_id,
+			    device_match->target_id,
+			    device_match->target_lun) != CAM_REQ_CMP)
+		return;
+
+	args->callback(enc, elem, cdm.ccb_h.path, args->callback_arg);
+	xpt_free_path(cdm.ccb_h.path);
+}
+
+/**
+ * \brief Iterate over and find the matching periph objects for the
+ *        specified element.
+ *
+ * \param enc	        SES instance containing elm
+ * \param elm	        Element for which to perform periph object matching.
+ * \param callback      The callback function to invoke with each matching
+ *                      periph object.
+ * \param callback_arg  Argument passed through to callback on each invocation.
+ */
+static void
+ses_paths_iter(enc_softc_t *enc, enc_element_t *elm,
+	       ses_path_callback_t *callback, void *callback_arg)
+{
+	ses_path_iter_args_t args;
+
+	args.callback     = callback;
+	args.callback_arg = callback_arg;
+	ses_devids_iter(enc, elm, ses_path_iter_devid_callback, &args);
+}
+
+/**
+ * ses_paths_iter() callback function used by ses_get_elmdevname()
+ * to record periph driver instance strings corresponding to a SES
+ * element.
+ *
+ * \param enc	  SES instance containing elm
+ * \param elm	  Element on which periph matching is active.
+ * \param periph  A periph instance that matches elm.
+ * \param arg     Argument passed through to callback on each invocation.
+ */
+static void
+ses_elmdevname_callback(enc_softc_t *enc, enc_element_t *elem,
+			struct cam_path *path, void *arg)
+{
+	struct sbuf *sb;
+
+	sb = (struct sbuf *)arg;
+	cam_periph_list(path, sb);
+}
+
+/**
+ * Argument package passed through ses_paths_iter() to
+ * ses_getcampath_callback.
+ */
+typedef struct ses_setphyspath_callback_args {
+	struct sbuf *physpath;
+	int          num_set;
+} ses_setphyspath_callback_args_t;
+
+/**
+ * \brief ses_paths_iter() callback to set the physical path on the
+ *        CAM EDT entries corresponding to a given SES element.
+ *
+ * \param enc	  SES instance containing elm
+ * \param elm	  Element on which periph matching is active.
+ * \param periph  A periph instance that matches elm.
+ * \param arg     Argument passed through to callback on each invocation.
+ */
+static void
+ses_setphyspath_callback(enc_softc_t *enc, enc_element_t *elm,
+			 struct cam_path *path, void *arg)
+{
+	struct ccb_dev_advinfo cdai;
+	ses_setphyspath_callback_args_t *args;
+	char *old_physpath;
+
+	args = (ses_setphyspath_callback_args_t *)arg;
+	old_physpath = malloc(MAXPATHLEN, M_SCSIENC, M_WAITOK|M_ZERO);
+
+	xpt_setup_ccb(&cdai.ccb_h, path, CAM_PRIORITY_NORMAL);
+	cdai.ccb_h.func_code = XPT_DEV_ADVINFO;
+	cdai.buftype = CDAI_TYPE_PHYS_PATH;
+	cdai.flags = 0;
+	cdai.bufsiz = MAXPATHLEN;
+	cdai.buf = old_physpath;
+	xpt_action((union ccb *)&cdai);
+	if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0)
+		cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE);
+
+	if (strcmp(old_physpath, sbuf_data(args->physpath)) != 0) {
+
+		xpt_setup_ccb(&cdai.ccb_h, path, CAM_PRIORITY_NORMAL);
+		cdai.ccb_h.func_code = XPT_DEV_ADVINFO;
+		cdai.buftype = CDAI_TYPE_PHYS_PATH;
+		cdai.flags |= CDAI_FLAG_STORE;
+		cdai.bufsiz = sbuf_len(args->physpath);
+		cdai.buf = sbuf_data(args->physpath);
+		xpt_action((union ccb *)&cdai);
+		if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0)
+			cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE);
+		if (cdai.ccb_h.status == CAM_REQ_CMP)
+			args->num_set++;
+	}
+	free(old_physpath, M_SCSIENC);
+}
+
+/**
+ * \brief Set a device's physical path string in CAM XPT.
+ *
+ * \param enc	SES instance containing elm
+ * \param elm	Element to publish physical path string for
+ * \param iter	Iterator whose state corresponds to elm
+ *
+ * \return	0 on success, errno otherwise.
+ */
+static int
+ses_set_physpath(enc_softc_t *enc, enc_element_t *elm,
+		 struct ses_iterator *iter)
+{
+	struct ccb_dev_advinfo cdai;
+	ses_setphyspath_callback_args_t args;
+	int ret;
+	struct sbuf sb;
+	uint8_t *devid, *elmaddr;
+	ses_element_t *elmpriv;
+
+	ret = EIO;
+	devid = NULL;
+
+	/*
+	 * Assemble the components of the physical path starting with
+	 * the device ID of the enclosure itself.
+	 */
+	xpt_setup_ccb(&cdai.ccb_h, enc->periph->path, CAM_PRIORITY_NORMAL);
+	cdai.ccb_h.func_code = XPT_DEV_ADVINFO;
+	cdai.buftype = CDAI_TYPE_SCSI_DEVID;
+	cdai.bufsiz = CAM_SCSI_DEVID_MAXLEN;
+	cdai.buf = devid = ENC_MALLOCZ(cdai.bufsiz);
+	if (devid == NULL) {
+		ret = ENOMEM;
+		goto out;
+	}
+	xpt_action((union ccb *)&cdai);
+	if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0)
+		cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE);
+	if (cdai.ccb_h.status != CAM_REQ_CMP)
+		goto out;
+
+	elmaddr = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf,
+	    cdai.provsiz, scsi_devid_is_naa_ieee_reg);
+	if (elmaddr == NULL)
+		goto out;
+
+	if (sbuf_new(&sb, NULL, 128, SBUF_AUTOEXTEND) == NULL) {
+		ret = ENOMEM;
+		goto out;
+	}
+	/* Next, generate the physical path string */
+	sbuf_printf(&sb, "id1,enc at n%jx/[email protected]%x/[email protected]%x",
+	    scsi_8btou64(elmaddr), iter->type_index,
+	    iter->type_element_index);
+	/* Append the element descriptor if one exists */
+	elmpriv = elm->elm_private;
+	if (elmpriv->descr != NULL && elmpriv->descr_len > 0) {
+		sbuf_cat(&sb, "/[email protected]");
+		sbuf_bcat(&sb, elmpriv->descr, elmpriv->descr_len);
+	}
+	sbuf_finish(&sb);
+
+	/*
+	 * Set this physical path on any CAM devices with a device ID
+	 * descriptor that matches one created from the SES additional
+	 * status data for this element.
+	 */
+	args.physpath= &sb;
+	args.num_set = 0;
+	ses_paths_iter(enc, elm, ses_setphyspath_callback, &args);
+	sbuf_delete(&sb);
+
+	ret = args.num_set == 0 ? ENOENT : 0;
+
+out:
+	if (devid != NULL)
+		ENC_FREE(devid);
+	return (ret);
+}
+
+/**
+ * \brief Helper to set the CDB fields appropriately.
+ *
+ * \param cdb		Buffer containing the cdb.
+ * \param pagenum	SES diagnostic page to query for.
+ * \param dir		Direction of query.
+ */
+static void
+ses_page_cdb(char *cdb, int bufsiz, SesDiagPageCodes pagenum, int dir)
+{
+
+	/* Ref: SPC-4 r25 Section 6.20 Table 223 */
+	if (dir == CAM_DIR_IN) {
+		cdb[0] = RECEIVE_DIAGNOSTIC;
+		cdb[1] = 1; /* Set page code valid bit */
+		cdb[2] = pagenum;
+	} else {
+		cdb[0] = SEND_DIAGNOSTIC;
+		cdb[1] = 0x10;
+		cdb[2] = pagenum;
+	}
+	cdb[3] = bufsiz >> 8;	/* high bits */
+	cdb[4] = bufsiz & 0xff;	/* low bits */
+	cdb[5] = 0;
+}
+
+/**
+ * \brief Discover whether this instance supports timed completion of a
+ * 	  RECEIVE DIAGNOSTIC RESULTS command requesting the Enclosure Status
+ * 	  page, and store the result in the softc, updating if necessary.
+ *
+ * \param enc	SES instance to query and update.
+ * \param tc_en	Value of timed completion to set (see \return).
+ *
+ * \return	1 if timed completion enabled, 0 otherwise.
+ */
+static int
+ses_set_timed_completion(enc_softc_t *enc, uint8_t tc_en)
+{
+	int err;
+	union ccb *ccb;
+	struct cam_periph *periph;
+	struct ses_mgmt_mode_page *mgmt;
+	uint8_t *mode_buf;
+	size_t mode_buf_len;
+	ses_softc_t *ses;
+
+	periph = enc->periph;
+	ses = enc->enc_private;
+	ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
+
+	mode_buf_len = sizeof(struct ses_mgmt_mode_page);
+	mode_buf = ENC_MALLOCZ(mode_buf_len);
+	if (mode_buf == NULL)
+		goto out;
+
+	scsi_mode_sense(&ccb->csio, /*retries*/4, enc_done, MSG_SIMPLE_Q_TAG,
+	    /*dbd*/FALSE, SMS_PAGE_CTRL_CURRENT, SES_MGMT_MODE_PAGE_CODE,
+	    mode_buf, mode_buf_len, SSD_FULL_SIZE, /*timeout*/60 * 1000);
+
+	/*
+	 * Ignore illegal request errors, as they are quite common and we
+	 * will print something out in that case anyway.
+	 */
+	err = cam_periph_runccb(ccb, enc_error, ENC_CFLAGS,
+	    ENC_FLAGS|SF_QUIET_IR, NULL);
+	if (ccb->ccb_h.status != CAM_REQ_CMP) {
+		ENC_LOG(enc, "Timed Completion Unsupported\n");
+		goto release;
+	}
+
+	/* Skip the mode select if the desired value is already set */
+	mgmt = (struct ses_mgmt_mode_page *)mode_buf;
+	if ((mgmt->byte5 & SES_MGMT_TIMED_COMP_EN) == tc_en)
+		goto done;
+
+	/* Value is not what we wanted, set it */
+	if (tc_en)
+		mgmt->byte5 |= SES_MGMT_TIMED_COMP_EN;
+	else
+		mgmt->byte5 &= ~SES_MGMT_TIMED_COMP_EN;
+	/* SES2r20: a completion time of zero means as long as possible */
+	bzero(&mgmt->max_comp_time, sizeof(mgmt->max_comp_time));
+
+	scsi_mode_select(&ccb->csio, 5, enc_done, MSG_SIMPLE_Q_TAG,
+	    /*page_fmt*/FALSE, /*save_pages*/TRUE, mode_buf, mode_buf_len,
+	    SSD_FULL_SIZE, /*timeout*/60 * 1000);
+
+	err = cam_periph_runccb(ccb, enc_error, ENC_CFLAGS, ENC_FLAGS, NULL);
+	if (ccb->ccb_h.status != CAM_REQ_CMP) {
+		ENC_LOG(enc, "Timed Completion Set Failed\n");
+		goto release;
+	}
+
+done:
+	if ((mgmt->byte5 & SES_MGMT_TIMED_COMP_EN) != 0) {
+		ENC_LOG(enc, "Timed Completion Enabled\n");
+		ses->ses_flags |= SES_FLAG_TIMEDCOMP;
+	} else {
+		ENC_LOG(enc, "Timed Completion Disabled\n");
+		ses->ses_flags &= ~SES_FLAG_TIMEDCOMP;
+	}
+release:
+	ENC_FREE(mode_buf);
+	xpt_release_ccb(ccb);
+out:
+	return (ses->ses_flags & SES_FLAG_TIMEDCOMP);
+}
+
+/**
+ * \brief Process the list of supported pages and update flags.
+ *
+ * \param enc       SES device to query.
+ * \param buf       Buffer containing the config page.
+ * \param xfer_len  Length of the config page in the buffer.
+ *
+ * \return  0 on success, errno otherwise.
+ */
+static int
+ses_process_pages(enc_softc_t *enc, struct enc_fsm_state *state,
+    union ccb *ccb, uint8_t **bufp, int error, int xfer_len)
+{
+	ses_softc_t *ses;
+	struct scsi_diag_page *page;
+	int err, i, length;
+
+	CAM_DEBUG(enc->periph->path, CAM_DEBUG_SUBTRACE,
+	    ("entering %s(%p, %d)\n", __func__, bufp, xfer_len));
+	ses = enc->enc_private;
+	err = -1;
+
+	if (error != 0) {
+		err = error;
+		goto out;
+	}
+	if (xfer_len < sizeof(*page)) {
+		ENC_LOG(enc, "Unable to parse Diag Pages List Header\n");
+		err = EIO;
+		goto out;
+	}
+	page = (struct scsi_diag_page *)*bufp;
+	length = scsi_2btoul(page->length);
+	if (length + offsetof(struct scsi_diag_page, params) > xfer_len) {
+		ENC_LOG(enc, "Diag Pages List Too Long\n");
+		goto out;
+	}
+	ENC_DLOG(enc, "%s: page length %d, xfer_len %d\n",
+		 __func__, length, xfer_len);
+
+	err = 0;
+	for (i = 0; i < length; i++) {
+		if (page->params[i] == SesAddlElementStatus) {
+			ses->ses_flags |= SES_FLAG_ADDLSTATUS;
+			break;
+		}
+	}
+
+out:
+	ENC_DLOG(enc, "%s: exiting with err %d\n", __func__, err);
+	return (err);
+}
+
+/**
+ * \brief Process the config page and update associated structures.
+ *
+ * \param enc       SES device to query.
+ * \param buf       Buffer containing the config page.
+ * \param xfer_len  Length of the config page in the buffer.
+ *
+ * \return  0 on success, errno otherwise.
+ */
+static int
+ses_process_config(enc_softc_t *enc, struct enc_fsm_state *state,
+    union ccb *ccb, uint8_t **bufp, int error, int xfer_len)
+{
+	struct ses_iterator iter;
+	ses_softc_t *ses;
+	enc_cache_t *enc_cache;
+	ses_cache_t *ses_cache;
+	uint8_t *buf;
+	int length;
+	int err;
+	int nelm;
+	int ntype;
+	struct ses_cfg_page *cfg_page;
+	struct ses_enc_desc *buf_subenc;
+	const struct ses_enc_desc **subencs;
+	const struct ses_enc_desc **cur_subenc;
+	const struct ses_enc_desc **last_subenc;
+	ses_type_t *ses_types;
+	ses_type_t *sestype;
+	const struct ses_elm_type_desc *cur_buf_type;
+	const struct ses_elm_type_desc *last_buf_type;
+	uint8_t *last_valid_byte;
+	enc_element_t *element;
+	const char *type_text;
+
+	CAM_DEBUG(enc->periph->path, CAM_DEBUG_SUBTRACE,
+	    ("entering %s(%p, %d)\n", __func__, bufp, xfer_len));
+	ses = enc->enc_private;
+	enc_cache = &enc->enc_daemon_cache;
+	ses_cache = enc_cache->private;
+	buf = *bufp;
+	err = -1;;
+
+	if (error != 0) {
+		err = error;
+		goto out;
+	}
+	if (xfer_len < sizeof(cfg_page->hdr)) {
+		ENC_LOG(enc, "Unable to parse SES Config Header\n");
+		err = EIO;
+		goto out;
+	}
+
+	cfg_page = (struct ses_cfg_page *)buf;
+	length = ses_page_length(&cfg_page->hdr);
+	if (length > xfer_len) {
+		ENC_LOG(enc, "Enclosure Config Page Too Long\n");
+		goto out;
+	}
+	last_valid_byte = &buf[length - 1];
+
+	ENC_DLOG(enc, "%s: total page length %d, xfer_len %d\n",
+		 __func__, length, xfer_len);
+
+	err = 0;
+	if (ses_config_cache_valid(ses_cache, cfg_page->hdr.gen_code)) {
+
+		/* Our cache is still valid.  Proceed to fetching status. */
+		goto out;
+	}
+
+	/* Cache is no longer valid.  Free old data to make way for new. */
+	ses_cache_free(enc, enc_cache);
+	ENC_VLOG(enc, "Generation Code 0x%x has %d SubEnclosures\n",
+	    scsi_4btoul(cfg_page->hdr.gen_code),
+	    ses_cfg_page_get_num_subenc(cfg_page));
+
+	/* Take ownership of the buffer. */
+	ses_cache->cfg_page = cfg_page;
+	*bufp = NULL;
+
+	/*
+	 * Now waltz through all the subenclosures summing the number of
+	 * types available in each.
+	 */
+	subencs = ENC_MALLOCZ(ses_cfg_page_get_num_subenc(cfg_page)
+			    * sizeof(*subencs));
+	if (subencs == NULL) {
+		err = ENOMEM;
+		goto out;
+	}
+	/*
+	 * Sub-enclosure data is const after construction (i.e. when
+	 * accessed via our cache object.
+	 *
+	 * The cast here is not required in C++ but C99 is not so
+	 * sophisticated (see C99 6.5.16.1(1)).
+	 */
+	ses_cache->subencs = subencs;
+
+	buf_subenc = cfg_page->subencs;
+	cur_subenc = subencs;
+	last_subenc = &subencs[ses_cfg_page_get_num_subenc(cfg_page) - 1];
+	ntype = 0;
+	while (cur_subenc <= last_subenc) {
+
+		if (!ses_enc_desc_is_complete(buf_subenc, last_valid_byte)) {
+			ENC_LOG(enc, "Enclosure %d Beyond End of "
+			    "Descriptors\n", cur_subenc - subencs);
+			err = EIO;
+			goto out;
+		}
+
+		ENC_VLOG(enc, " SubEnclosure ID %d, %d Types With this ID, "
+		    "Descriptor Length %d, offset %d\n", buf_subenc->subenc_id,
+		    buf_subenc->num_types, buf_subenc->length,
+		    &buf_subenc->byte0 - buf);
+		ENC_VLOG(enc, "WWN: %jx\n",
+		    (uintmax_t)scsi_8btou64(buf_subenc->logical_id));
+
+		ntype += buf_subenc->num_types;
+		*cur_subenc = buf_subenc;
+		cur_subenc++;
+		buf_subenc = ses_enc_desc_next(buf_subenc);
+	}
+
+	/* Process the type headers. */
+	ses_types = ENC_MALLOCZ(ntype * sizeof(*ses_types));
+	if (ses_types == NULL) {
+		err = ENOMEM;
+		goto out;
+	}
+	/*
+	 * Type data is const after construction (i.e. when accessed via
+	 * our cache object.
+	 */
+	ses_cache->ses_types = ses_types;
+
+	cur_buf_type = (const struct ses_elm_type_desc *)
+	    (&(*last_subenc)->length + (*last_subenc)->length + 1);
+	last_buf_type = cur_buf_type + ntype - 1;
+	type_text = (const uint8_t *)(last_buf_type + 1);
+	nelm = 0;
+	sestype = ses_types;
+	while (cur_buf_type <= last_buf_type) {
+		if (&cur_buf_type->etype_txt_len > last_valid_byte) {
+			ENC_LOG(enc, "Runt Enclosure Type Header %d\n",
+			    sestype - ses_types);
+			err = EIO;
+			goto out;
+		}
+		sestype->hdr  = cur_buf_type;
+		sestype->text = type_text;
+		type_text += cur_buf_type->etype_txt_len;
+		ENC_LOG(enc, " Type Desc[%d]: Type 0x%x, MaxElt %d, In Subenc "
+		    "%d, Text Length %d: %.*s\n", sestype - ses_types,
+		    sestype->hdr->etype_elm_type, sestype->hdr->etype_maxelt,
+		    sestype->hdr->etype_subenc, sestype->hdr->etype_txt_len,
+		    sestype->hdr->etype_txt_len, sestype->text);
+
+		nelm += sestype->hdr->etype_maxelt
+		      + /*overall status element*/1;
+		sestype++;
+		cur_buf_type++;
+	}
+
+	/* Create the object map. */
+	enc_cache->elm_map = ENC_MALLOCZ(nelm * sizeof(enc_element_t));
+	if (enc_cache->elm_map == NULL) {
+		err = ENOMEM;
+		goto out;
+	}
+	ses_cache->ses_ntypes = (uint8_t)ntype;
+	enc_cache->nelms = nelm;
+
+	ses_iter_init(enc, enc_cache, &iter);
+	while ((element = ses_iter_next(&iter)) != NULL) {
+		const struct ses_elm_type_desc *thdr;
+
+		ENC_DLOG(enc, "%s: checking obj %d(%d,%d)\n", __func__,
+		    iter.global_element_index, iter.type_index, nelm,
+		    iter.type_element_index);
+		thdr = ses_cache->ses_types[iter.type_index].hdr;
+		element->subenclosure = thdr->etype_subenc;
+		element->enctype = thdr->etype_elm_type;
+		element->overall_status_elem = iter.type_element_index == 0;
+		element->elm_private = ENC_MALLOCZ(sizeof(ses_element_t));
+		if (element->elm_private == NULL) {
+			err = ENOMEM;
+			goto out;
+		}
+		ENC_DLOG(enc, "%s: creating elmpriv %d(%d,%d) subenc %d "
+		    "type 0x%x\n", __func__, iter.global_element_index,
+		    iter.type_index, iter.type_element_index,
+		    thdr->etype_subenc, thdr->etype_elm_type);
+	}
+
+	err = 0;
+
+out:
+	if (err)
+		ses_cache_free(enc, enc_cache);
+	else {
+		enc_update_request(enc, SES_UPDATE_GETSTATUS);
+		enc_update_request(enc, SES_UPDATE_GETELMDESCS);
+		if (ses->ses_flags & SES_FLAG_ADDLSTATUS)
+			enc_update_request(enc, SES_UPDATE_GETELMADDLSTATUS);
+		enc_update_request(enc, SES_PUBLISH_CACHE);
+	}
+	ENC_DLOG(enc, "%s: exiting with err %d\n", __func__, err);
+	return (err);
+}
+
+/**
+ * \brief Update the status page and associated structures.
+ * 
+ * \param enc   SES softc to update for.
+ * \param buf   Buffer containing the status page.
+ * \param bufsz	Amount of data in the buffer.
+ *
+ * \return	0 on success, errno otherwise.
+ */
+static int
+ses_process_status(enc_softc_t *enc, struct enc_fsm_state *state,
+    union ccb *ccb, uint8_t **bufp, int error, int xfer_len)
+{
+	struct ses_iterator iter;
+	enc_element_t *element;
+	ses_softc_t *ses;
+	enc_cache_t *enc_cache;
+	ses_cache_t *ses_cache;
+	uint8_t *buf;
+	int err = -1;
+	int length;
+	struct ses_status_page *page;
+	union ses_status_element *cur_stat;
+	union ses_status_element *last_stat;
+
+	ses = enc->enc_private;
+	enc_cache = &enc->enc_daemon_cache;
+	ses_cache = enc_cache->private;
+	buf = *bufp;
+
+	ENC_DLOG(enc, "%s: enter (%p, %p, %d)\n", __func__, enc, buf, xfer_len);
+	page = (struct ses_status_page *)buf;
+	length = ses_page_length(&page->hdr);
+
+	if (error != 0) {
+		err = error;
+		goto out;
+	}
+	/*
+	 * Make sure the length fits in the buffer.
+	 *
+	 * XXX all this means is that the page is larger than the space
+	 * we allocated.  Since we use a statically sized buffer, this
+	 * could happen... Need to use dynamic discovery of the size.
+	 */
+	if (length > xfer_len) {
+		ENC_LOG(enc, "Enclosure Status Page Too Long\n");
+		goto out;
+	}
+	/* Make sure the length contains at least one header and status */
+	if (length < (sizeof(*page) + sizeof(*page->elements))) {
+		ENC_LOG(enc, "Enclosure Status Page Too Short\n");
+		goto out;
+	}
+
+	if (!ses_config_cache_valid(ses_cache, page->hdr.gen_code)) {
+		ENC_DLOG(enc, "%s: Generation count change detected\n",
+		    __func__);
+		enc_update_request(enc, SES_UPDATE_GETCONFIG);
+		goto out;
+	}
+
+	ses_cache_free_status(enc, enc_cache);
+	ses_cache->status_page = page;
+	*bufp = NULL;
+
+	enc_cache->enc_status = page->hdr.page_specific_flags;
+
+	/*
+	 * Read in individual element status.  The element order
+	 * matches the order reported in the config page (i.e. the
+	 * order of an unfiltered iteration of the config objects)..
+	 */
+	ses_iter_init(enc, enc_cache, &iter);
+	cur_stat  = page->elements;
+	last_stat = (union ses_status_element *)
+	    &buf[length - sizeof(*last_stat)];
+	ENC_DLOG(enc, "%s: total page length %d, xfer_len %d\n",
+		__func__, length, xfer_len);
+	while (cur_stat <= last_stat
+	    && (element = ses_iter_next(&iter)) != NULL) {
+
+		ENC_DLOG(enc, "%s: obj %d(%d,%d) off=0x%tx status=%jx\n",
+		    __func__, iter.global_element_index, iter.type_index,
+		    iter.type_element_index, (uint8_t *)cur_stat - buf,
+		    scsi_4btoul(cur_stat->bytes));
+
+		memcpy(&element->encstat, cur_stat, sizeof(element->encstat));
+		element->svalid = 1;
+		cur_stat++;
+	}
+
+	if (ses_iter_next(&iter) != NULL) {
+		ENC_LOG(enc, "Status page, length insufficient for "
+			"expected number of objects\n");
+	} else {
+		if (cur_stat <= last_stat)
+			ENC_LOG(enc, "Status page, exhausted objects before "
+				"exhausing page\n");
+		enc_update_request(enc, SES_PUBLISH_CACHE);
+		err = 0;
+	}
+out:
+	ENC_DLOG(enc, "%s: exiting with error %d\n", __func__, err);
+	return (err);
+}
+
+typedef enum {
+	/**
+	 * The enclosure should not provide additional element
+	 * status for this element type in page 0x0A.
+	 *
+	 * \note  This status is returned for any types not
+	 *        listed SES3r02.  Further types added in a
+	 *        future specification will be incorrectly
+	 *        classified.
+	 */
+	TYPE_ADDLSTATUS_NONE,
+
+	/**
+	 * The element type provides additional element status
+	 * in page 0x0A.
+	 */
+	TYPE_ADDLSTATUS_MANDATORY,
+
+	/**
+	 * The element type may provide additional element status
+	 * in page 0x0A, but i
+	 */
+	TYPE_ADDLSTATUS_OPTIONAL
+} ses_addlstatus_avail_t;
+
+/**
+ * \brief Check to see whether a given type (as obtained via type headers) is
+ *	  supported by the additional status command.
+ *
+ * \param enc     SES softc to check.
+ * \param typidx  Type index to check for.
+ *
+ * \return  An enumeration indicating if additional status is mandatory,
+ *          optional, or not required for this type.
+ */
+static ses_addlstatus_avail_t
+ses_typehasaddlstatus(enc_softc_t *enc, uint8_t typidx)
+{
+	enc_cache_t *enc_cache;
+	ses_cache_t *ses_cache;
+
+	enc_cache = &enc->enc_daemon_cache;
+	ses_cache = enc_cache->private;
+	switch(ses_cache->ses_types[typidx].hdr->etype_elm_type) {
+	case ELMTYP_DEVICE:
+	case ELMTYP_ARRAY_DEV:
+	case ELMTYP_SAS_EXP:
+		return (TYPE_ADDLSTATUS_MANDATORY);
+	case ELMTYP_SCSI_INI:
+	case ELMTYP_SCSI_TGT:
+	case ELMTYP_ESCC:
+		return (TYPE_ADDLSTATUS_OPTIONAL);
+	default:
+		/* No additional status information available. */
+		break;
+	}
+	return (TYPE_ADDLSTATUS_NONE);
+}
+
+static int ses_get_elm_addlstatus_fc(enc_softc_t *, enc_cache_t *,
+				     uint8_t *, int);
+static int ses_get_elm_addlstatus_sas(enc_softc_t *, enc_cache_t *, uint8_t *,
+				      int, int, int, int);
+
+/**
+ * \brief Parse the additional status element data for each object.
+ *
+ * \param enc       The SES softc to update.
+ * \param buf       The buffer containing the additional status
+ *                  element response.
+ * \param xfer_len  Size of the buffer.
+ *
+ * \return  0 on success, errno otherwise.
+ */
+static int
+ses_process_elm_addlstatus(enc_softc_t *enc, struct enc_fsm_state *state,
+    union ccb *ccb, uint8_t **bufp, int error, int xfer_len)
+{
+	struct ses_iterator iter, titer;
+	int eip;
+	int err;
+	int ignore_index = 0;
+	int length;
+	int offset;
+	enc_cache_t *enc_cache;
+	ses_cache_t *ses_cache;
+	uint8_t *buf;
+	ses_element_t *elmpriv;
+	const struct ses_page_hdr *hdr;
+	enc_element_t *element, *telement;
+
+	enc_cache = &enc->enc_daemon_cache;
+	ses_cache = enc_cache->private;
+	buf = *bufp;
+	err = -1;
+
+	if (error != 0) {
+		err = error;
+		goto out;
+	}
+	ses_cache_free_elm_addlstatus(enc, enc_cache);
+	ses_cache->elm_addlstatus_page =
+	    (struct ses_addl_elem_status_page *)buf;
+	*bufp = NULL;
+
+	/*
+	 * The objects appear in the same order here as in Enclosure Status,
+	 * which itself is ordered by the Type Descriptors from the Config
+	 * page.  However, it is necessary to skip elements that are not
+	 * supported by this page when counting them.
+	 */
+	hdr = &ses_cache->elm_addlstatus_page->hdr;
+	length = ses_page_length(hdr);
+	ENC_DLOG(enc, "Additional Element Status Page Length 0x%x\n", length);
+	/* Make sure the length includes at least one header. */
+	if (length < sizeof(*hdr)+sizeof(struct ses_elm_addlstatus_base_hdr)) {
+		ENC_LOG(enc, "Runt Additional Element Status Page\n");
+		goto out;
+	}
+	if (length > xfer_len) {
+		ENC_LOG(enc, "Additional Element Status Page Too Long\n");
+		goto out;
+	}
+
+	if (!ses_config_cache_valid(ses_cache, hdr->gen_code)) {
+		ENC_DLOG(enc, "%s: Generation count change detected\n",
+		    __func__);
+		enc_update_request(enc, SES_UPDATE_GETCONFIG);
+		goto out;
+	}
+
+	offset = sizeof(struct ses_page_hdr);
+	ses_iter_init(enc, enc_cache, &iter);
+	while (offset < length
+	    && (element = ses_iter_next(&iter)) != NULL) {
+		struct ses_elm_addlstatus_base_hdr *elm_hdr;
+		int proto_info_len;
+		ses_addlstatus_avail_t status_type;
+
+		/*
+		 * Additional element status is only provided for
+		 * individual elements (i.e. overal status elements
+		 * are excluded) and those of the types specified
+		 * in the SES spec.
+		 */
+		status_type = ses_typehasaddlstatus(enc, iter.type_index);
+		if (iter.individual_element_index == ITERATOR_INDEX_INVALID
+		 || status_type == TYPE_ADDLSTATUS_NONE)
+			continue;
+
+		elm_hdr = (struct ses_elm_addlstatus_base_hdr *)&buf[offset];
+		eip = ses_elm_addlstatus_eip(elm_hdr);
+		if (eip && !ignore_index) {
+			struct ses_elm_addlstatus_eip_hdr *eip_hdr;
+			int expected_index;
+
+			eip_hdr = (struct ses_elm_addlstatus_eip_hdr *)elm_hdr;
+			expected_index = iter.individual_element_index;
+			titer = iter;
+			telement = ses_iter_seek_to(&titer,
+						   eip_hdr->element_index,
+						   SES_ELEM_INDEX_INDIVIDUAL);
+			if (telement != NULL &&
+			    (ses_typehasaddlstatus(enc, titer.type_index) !=
+			     TYPE_ADDLSTATUS_NONE ||
+			     titer.type_index > ELMTYP_SAS_CONN)) {
+				iter = titer;
+				element = telement;
+			} else
+				ignore_index = 1;
+
+			if (iter.individual_element_index > expected_index
+			 && status_type == TYPE_ADDLSTATUS_MANDATORY) {
+				ENC_LOG(enc, "%s: provided element "
+					"index %d skips mandatory status "
+					" element at index %d\n",
+					__func__, eip_hdr->element_index,
+					expected_index);
+			}
+		}
+		elmpriv = element->elm_private;
+		elmpriv->addl.hdr = elm_hdr;
+		ENC_DLOG(enc, "%s: global element index=%d, type index=%d "
+		    "type element index=%d, offset=0x%x, "
+		    "byte0=0x%x, length=0x%x\n", __func__,
+		    iter.global_element_index, iter.type_index,
+		    iter.type_element_index, offset, elmpriv->addl.hdr->byte0,
+		    elmpriv->addl.hdr->length);
+
+		/* Skip to after the length field */
+		offset += sizeof(struct ses_elm_addlstatus_base_hdr);
+
+		/* Make sure the descriptor is within bounds */
+		if ((offset + elmpriv->addl.hdr->length) > length) {
+			ENC_LOG(enc, "Element %d Beyond End "
+			    "of Additional Element Status Descriptors\n",
+			    iter.global_element_index);
+			err = EIO;
+			goto out;
+		}
+
+		/* Advance to the protocol data, skipping eip bytes if needed */
+		offset += (eip * SES_EIP_HDR_EXTRA_LEN);
+		proto_info_len = elmpriv->addl.hdr->length
+			       - (eip * SES_EIP_HDR_EXTRA_LEN);
+
+		/* Errors in this block are ignored as they are non-fatal */
+		switch(ses_elm_addlstatus_proto(elmpriv->addl.hdr)) {
+		case SPSP_PROTO_FC:
+			if (elmpriv->addl.hdr->length == 0)
+				break;
+			ses_get_elm_addlstatus_fc(enc, enc_cache,
+						  &buf[offset], proto_info_len);
+			break;
+		case SPSP_PROTO_SAS:
+			if (elmpriv->addl.hdr->length <= 2)
+				break;
+			ses_get_elm_addlstatus_sas(enc, enc_cache,
+						   &buf[offset],
+						   proto_info_len,
+						   eip, iter.type_index,
+						   iter.global_element_index);
+			break;
+		default:
+			ENC_LOG(enc, "Element %d: Unknown Additional Element "
+			    "Protocol 0x%x\n", iter.global_element_index,
+			    ses_elm_addlstatus_proto(elmpriv->addl.hdr));
+			goto out;
+		}
+
+		offset += proto_info_len;
+	}
+	err = 0;
+out:
+	if (err)
+		ses_cache_free_elm_addlstatus(enc, enc_cache);
+	enc_update_request(enc, SES_PUBLISH_PHYSPATHS);
+	enc_update_request(enc, SES_PUBLISH_CACHE);
+	return (err);
+}
+
+static int
+ses_process_control_request(enc_softc_t *enc, struct enc_fsm_state *state,
+    union ccb *ccb, uint8_t **bufp, int error, int xfer_len)
+{
+	ses_softc_t *ses;
+
+	ses = enc->enc_private;
+	/*
+	 * Possible errors:
+	 *  o Generation count wrong.
+	 *  o Some SCSI status error.
+	 */
+	ses_terminate_control_requests(&ses->ses_pending_requests, error);
+	enc_update_request(enc, SES_UPDATE_GETSTATUS);
+	return (0);
+}
+
+static int
+ses_publish_physpaths(enc_softc_t *enc, struct enc_fsm_state *state,
+    union ccb *ccb, uint8_t **bufp, int error, int xfer_len)
+{
+	struct ses_iterator iter;
+	enc_cache_t *enc_cache;
+	ses_cache_t *ses_cache;
+	enc_element_t *element;
+
+	enc_cache = &enc->enc_daemon_cache;
+	ses_cache = enc_cache->private;
+
+	ses_iter_init(enc, enc_cache, &iter);
+	while ((element = ses_iter_next(&iter)) != NULL) {
+		/*
+		 * ses_set_physpath() returns success if we changed
+		 * the physpath of any element.  This allows us to
+		 * only announce devices once regardless of how
+		 * many times we process additional element status.
+		 */
+		if (ses_set_physpath(enc, element, &iter) == 0)
+			ses_print_addl_data(enc, element);
+	}
+
+	return (0);
+}
+
+static int
+ses_publish_cache(enc_softc_t *enc, struct enc_fsm_state *state,
+    union ccb *ccb, uint8_t **bufp, int error, int xfer_len)
+{
+
+	sx_xlock(&enc->enc_cache_lock);
+	ses_cache_clone(enc, /*src*/&enc->enc_daemon_cache,
+			/*dst*/&enc->enc_cache);
+	sx_xunlock(&enc->enc_cache_lock);
+
+	return (0);
+}
+
+/**
+ * \brief Parse the descriptors for each object.
+ *
+ * \param enc       The SES softc to update.
+ * \param buf       The buffer containing the descriptor list response.
+ * \param xfer_len  Size of the buffer.
+ * 
+ * \return	0 on success, errno otherwise.
+ */
+static int
+ses_process_elm_descs(enc_softc_t *enc, struct enc_fsm_state *state,
+    union ccb *ccb, uint8_t **bufp, int error, int xfer_len)
+{
+	ses_softc_t *ses;
+	struct ses_iterator iter;
+	enc_element_t *element;
+	int err;
+	int offset;
+	u_long length, plength;
+	enc_cache_t *enc_cache;
+	ses_cache_t *ses_cache;
+	uint8_t *buf;
+	ses_element_t *elmpriv;
+	const struct ses_page_hdr *phdr;
+	const struct ses_elm_desc_hdr *hdr;
+
+	ses = enc->enc_private;
+	enc_cache = &enc->enc_daemon_cache;
+	ses_cache = enc_cache->private;
+	buf = *bufp;
+	err = -1;
+
+	if (error != 0) {
+		err = error;
+		goto out;
+	}
+	ses_cache_free_elm_descs(enc, enc_cache);
+	ses_cache->elm_descs_page = (struct ses_elem_descr_page *)buf;
+	*bufp = NULL;
+
+	phdr = &ses_cache->elm_descs_page->hdr;
+	plength = ses_page_length(phdr);
+	if (xfer_len < sizeof(struct ses_page_hdr)) {
+		ENC_LOG(enc, "Runt Element Descriptor Page\n");
+		goto out;
+	}
+	if (plength > xfer_len) {
+		ENC_LOG(enc, "Element Descriptor Page Too Long\n");
+		goto out;
+	}
+
+	if (!ses_config_cache_valid(ses_cache, phdr->gen_code)) {
+		ENC_VLOG(enc, "%s: Generation count change detected\n",
+		    __func__);
+		enc_update_request(enc, SES_UPDATE_GETCONFIG);
+		goto out;
+	}
+
+	offset = sizeof(struct ses_page_hdr);
+
+	ses_iter_init(enc, enc_cache, &iter);
+	while (offset < plength
+	    && (element = ses_iter_next(&iter)) != NULL) {
+
+		if ((offset + sizeof(struct ses_elm_desc_hdr)) > plength) {
+			ENC_LOG(enc, "Element %d Descriptor Header Past "
+			    "End of Buffer\n", iter.global_element_index);
+			goto out;
+		}
+		hdr = (struct ses_elm_desc_hdr *)&buf[offset];
+		length = scsi_2btoul(hdr->length);
+		ENC_DLOG(enc, "%s: obj %d(%d,%d) length=%d off=%d\n", __func__,
+		    iter.global_element_index, iter.type_index,
+		    iter.type_element_index, length, offset);
+		if ((offset + sizeof(*hdr) + length) > plength) {
+			ENC_LOG(enc, "Element%d Descriptor Past "
+			    "End of Buffer\n", iter.global_element_index);
+			goto out;
+		}
+		offset += sizeof(*hdr);
+
+		if (length > 0) {
+			elmpriv = element->elm_private;
+			elmpriv->descr_len = length;
+			elmpriv->descr = &buf[offset];
+		}
+
+		/* skip over the descriptor itself */
+		offset += length;
+	}
+
+	err = 0;
+out:
+	if (err == 0) {
+		if (ses->ses_flags & SES_FLAG_ADDLSTATUS)
+			enc_update_request(enc, SES_UPDATE_GETELMADDLSTATUS);
+	}
+	enc_update_request(enc, SES_PUBLISH_CACHE);
+	return (err);
+}
+
+static int
+ses_fill_rcv_diag_io(enc_softc_t *enc, struct enc_fsm_state *state,
+		       union ccb *ccb, uint8_t *buf)
+{
+
+	if (enc->enc_type == ENC_SEMB_SES) {
+		semb_receive_diagnostic_results(&ccb->ataio, /*retries*/5,
+					enc_done, MSG_SIMPLE_Q_TAG, /*pcv*/1,
+					state->page_code, buf, state->buf_size,
+					state->timeout);
+	} else {
+		scsi_receive_diagnostic_results(&ccb->csio, /*retries*/5,
+					enc_done, MSG_SIMPLE_Q_TAG, /*pcv*/1,
+					state->page_code, buf, state->buf_size,
+					SSD_FULL_SIZE, state->timeout);
+	}
+	return (0);
+}
+
+/**
+ * \brief Encode the object status into the response buffer, which is
+ *	  expected to contain the current enclosure status.  This function
+ *	  turns off all the 'select' bits for the objects except for the
+ *	  object specified, then sends it back to the enclosure.
+ *
+ * \param enc	SES enclosure the change is being applied to.
+ * \param buf	Buffer containing the current enclosure status response.
+ * \param amt	Length of the response in the buffer.
+ * \param req	The control request to be applied to buf.
+ *
+ * \return	0 on success, errno otherwise.
+ */
+static int
+ses_encode(enc_softc_t *enc, uint8_t *buf, int amt, ses_control_request_t *req)
+{
+	struct ses_iterator iter;
+	enc_element_t *element;
+	int offset;
+	struct ses_control_page_hdr *hdr;
+
+	ses_iter_init(enc, &enc->enc_cache, &iter);
+	hdr = (struct ses_control_page_hdr *)buf;
+	if (req->elm_idx == -1) {
+		/* for enclosure status, at least 2 bytes are needed */
+		if (amt < 2)
+			return EIO;
+		hdr->control_flags =
+		    req->elm_stat.comstatus & SES_SET_STATUS_MASK;
+		ENC_DLOG(enc, "Set EncStat %x\n", hdr->control_flags);
+		return (0);
+	}
+
+	element = ses_iter_seek_to(&iter, req->elm_idx, SES_ELEM_INDEX_GLOBAL);
+	if (element == NULL)
+		return (ENXIO);
+
+	/*
+	 * Seek to the type set that corresponds to the requested object.
+	 * The +1 is for the overall status element for the type.
+	 */
+	offset = sizeof(struct ses_control_page_hdr)
+	       + (iter.global_element_index * sizeof(struct ses_comstat));
+
+	/* Check for buffer overflow. */
+	if (offset + sizeof(struct ses_comstat) > amt)
+		return (EIO);
+
+	/* Set the status. */
+	memcpy(&buf[offset], &req->elm_stat, sizeof(struct ses_comstat));
+
+	ENC_DLOG(enc, "Set Type 0x%x Obj 0x%x (offset %d) with %x %x %x %x\n",
+	    iter.type_index, iter.global_element_index, offset,
+	    req->elm_stat.comstatus, req->elm_stat.comstat[0],
+	    req->elm_stat.comstat[1], req->elm_stat.comstat[2]);
+
+	return (0);
+}
+
+static int
+ses_fill_control_request(enc_softc_t *enc, struct enc_fsm_state *state,
+			 union ccb *ccb, uint8_t *buf)
+{
+	ses_softc_t			*ses;
+	enc_cache_t			*enc_cache;
+	ses_cache_t			*ses_cache;
+	struct ses_control_page_hdr	*hdr;
+	ses_control_request_t		*req;
+	size_t				 plength;
+	size_t				 offset;
+
+	ses = enc->enc_private;
+	enc_cache = &enc->enc_daemon_cache;
+	ses_cache = enc_cache->private;
+	hdr = (struct ses_control_page_hdr *)buf;
+	
+	if (ses_cache->status_page == NULL) {
+		ses_terminate_control_requests(&ses->ses_requests, EIO);
+		return (EIO);
+	}
+
+	plength = ses_page_length(&ses_cache->status_page->hdr);
+	memcpy(buf, ses_cache->status_page, plength);
+
+	/* Disable the select bits in all status entries.  */
+	offset = sizeof(struct ses_control_page_hdr);
+	for (offset = sizeof(struct ses_control_page_hdr);
+	     offset < plength; offset += sizeof(struct ses_comstat)) {
+		buf[offset] &= ~SESCTL_CSEL;
+	}
+
+	/* And make sure the INVOP bit is clear.  */
+	hdr->control_flags &= ~SES_ENCSTAT_INVOP;
+
+	/* Apply incoming requests. */
+	while ((req = TAILQ_FIRST(&ses->ses_requests)) != NULL) {
+
+		TAILQ_REMOVE(&ses->ses_requests, req, links);
+		req->result = ses_encode(enc, buf, plength, req);
+		if (req->result != 0) {
+			wakeup(req);
+			continue;
+		}
+		TAILQ_INSERT_TAIL(&ses->ses_pending_requests, req, links);
+	}
+
+	if (TAILQ_EMPTY(&ses->ses_pending_requests) != 0)
+		return (ENOENT);
+
+	/* Fill out the ccb */
+	if (enc->enc_type == ENC_SEMB_SES) {
+		semb_send_diagnostic(&ccb->ataio, /*retries*/5, enc_done,
+			     MSG_SIMPLE_Q_TAG,
+			     buf, ses_page_length(&ses_cache->status_page->hdr),
+			     state->timeout);
+	} else {
+		scsi_send_diagnostic(&ccb->csio, /*retries*/5, enc_done,
+			     MSG_SIMPLE_Q_TAG, /*unit_offline*/0,
+			     /*device_offline*/0, /*self_test*/0,
+			     /*page_format*/1, /*self_test_code*/0,
+			     buf, ses_page_length(&ses_cache->status_page->hdr),
+			     SSD_FULL_SIZE, state->timeout);
+	}
+	return (0);
+}
+
+static int
+ses_get_elm_addlstatus_fc(enc_softc_t *enc, enc_cache_t *enc_cache,
+			  uint8_t *buf, int bufsiz)
+{
+	ENC_LOG(enc, "FC Device Support Stubbed in Additional Status Page\n");
+	return (ENODEV);
+}
+
+#define	SES_PRINT_PORTS(p, type) do {					\
+	sbuf_printf(sbp, " %s(", type);					\
+	if (((p) & SES_SASOBJ_DEV_PHY_PROTOMASK) == 0)			\
+		sbuf_printf(sbp, " None");				\
+	else {								\
+		if ((p) & SES_SASOBJ_DEV_PHY_SMP)			\
+			sbuf_printf(sbp, " SMP");			\
+		if ((p) & SES_SASOBJ_DEV_PHY_STP)			\
+			sbuf_printf(sbp, " STP");			\
+		if ((p) & SES_SASOBJ_DEV_PHY_SSP)			\
+			sbuf_printf(sbp, " SSP");			\
+	}								\
+	sbuf_printf(sbp, " )");						\
+} while(0)
+
+/**
+ * \brief Print the additional element status data for this object, for SAS
+ * 	  type 0 objects.  See SES2 r20 Section 6.1.13.3.2.
+ *
+ * \param sesname	SES device name associated with the object.
+ * \param sbp		Sbuf to print to.
+ * \param obj		The object to print the data for.
+ * \param periph_name	Peripheral string associated with the object.
+ */
+static void
+ses_print_addl_data_sas_type0(char *sesname, struct sbuf *sbp,
+			      enc_element_t *obj, char *periph_name)
+{
+	int i;
+	ses_element_t *elmpriv;
+	struct ses_addl_status *addl;
+	struct ses_elm_sas_device_phy *phy;
+
+	elmpriv = obj->elm_private;
+	addl = &(elmpriv->addl);
+	if (addl->proto_hdr.sas == NULL)
+		return;
+	sbuf_printf(sbp, "%s: %s: SAS Device Slot Element:",
+	    sesname, periph_name);
+	sbuf_printf(sbp, " %d Phys", addl->proto_hdr.sas->base_hdr.num_phys);
+	if (ses_elm_addlstatus_eip(addl->hdr))
+		sbuf_printf(sbp, " at Slot %d",
+		    addl->proto_hdr.sas->type0_eip.dev_slot_num);
+	if (ses_elm_sas_type0_not_all_phys(addl->proto_hdr.sas))
+		sbuf_printf(sbp, ", Not All Phys");
+	sbuf_printf(sbp, "\n");
+	if (addl->proto_data.sasdev_phys == NULL)
+		return;
+	for (i = 0;i < addl->proto_hdr.sas->base_hdr.num_phys;i++) {
+		phy = &addl->proto_data.sasdev_phys[i];
+		sbuf_printf(sbp, "%s:  phy %d:", sesname, i);
+		if (ses_elm_sas_dev_phy_sata_dev(phy))
+			/* Spec says all other fields are specific values */
+			sbuf_printf(sbp, " SATA device\n");
+		else {
+			sbuf_printf(sbp, " SAS device type %d id %d\n",
+			    ses_elm_sas_dev_phy_dev_type(phy), phy->phy_id);
+			sbuf_printf(sbp, "%s:  phy %d: protocols:", sesname, i);
+			SES_PRINT_PORTS(phy->initiator_ports, "Initiator");
+			SES_PRINT_PORTS(phy->target_ports, "Target");
+			sbuf_printf(sbp, "\n");
+		}
+		sbuf_printf(sbp, "%s:  phy %d: parent %jx addr %jx\n",
+		    sesname, i,
+		    (uintmax_t)scsi_8btou64(phy->parent_addr),
+		    (uintmax_t)scsi_8btou64(phy->phy_addr));
+	}
+}
+#undef SES_PRINT_PORTS
+
+/**
+ * \brief Report whether a given enclosure object is an expander.
+ *
+ * \param enc	SES softc associated with object.
+ * \param obj	Enclosure object to report for.
+ *
+ * \return	1 if true, 0 otherwise.
+ */
+static int
+ses_obj_is_expander(enc_softc_t *enc, enc_element_t *obj)
+{
+	return (obj->enctype == ELMTYP_SAS_EXP);
+}
+
+/**
+ * \brief Print the additional element status data for this object, for SAS
+ *	  type 1 objects.  See SES2 r20 Sections 6.1.13.3.3 and 6.1.13.3.4.
+ *
+ * \param enc		SES enclosure, needed for type identification.
+ * \param sesname	SES device name associated with the object.
+ * \param sbp		Sbuf to print to.
+ * \param obj		The object to print the data for.
+ * \param periph_name	Peripheral string associated with the object.
+ */
+static void
+ses_print_addl_data_sas_type1(enc_softc_t *enc, char *sesname,
+    struct sbuf *sbp, enc_element_t *obj, char *periph_name)
+{
+	int i, num_phys;
+	ses_element_t *elmpriv;
+	struct ses_addl_status *addl;
+	struct ses_elm_sas_expander_phy *exp_phy;
+	struct ses_elm_sas_port_phy *port_phy;
+
+	elmpriv = obj->elm_private;
+	addl = &(elmpriv->addl);
+	if (addl->proto_hdr.sas == NULL)
+		return;
+	sbuf_printf(sbp, "%s: %s: SAS ", sesname, periph_name);
+	if (ses_obj_is_expander(enc, obj)) {
+		num_phys = addl->proto_hdr.sas->base_hdr.num_phys;
+		sbuf_printf(sbp, "Expander: %d Phys", num_phys);
+		if (addl->proto_data.sasexp_phys == NULL)
+			return;
+		for (i = 0;i < num_phys;i++) {
+			exp_phy = &addl->proto_data.sasexp_phys[i];
+			sbuf_printf(sbp, "%s:  phy %d: connector %d other %d\n",
+			    sesname, i, exp_phy->connector_index,
+			    exp_phy->other_index);
+		}
+	} else {
+		num_phys = addl->proto_hdr.sas->base_hdr.num_phys;
+		sbuf_printf(sbp, "Port: %d Phys", num_phys);
+		if (addl->proto_data.sasport_phys == NULL)
+			return;
+		for (i = 0;i < num_phys;i++) {
+			port_phy = &addl->proto_data.sasport_phys[i];
+			sbuf_printf(sbp,
+			    "%s:  phy %d: id %d connector %d other %d\n",
+			    sesname, i, port_phy->phy_id,
+			    port_phy->connector_index, port_phy->other_index);
+			sbuf_printf(sbp, "%s:  phy %d: addr %jx\n", sesname, i,
+			    (uintmax_t)scsi_8btou64(port_phy->phy_addr));
+		}
+	}
+}
+
+/**
+ * \brief Print the additional element status data for this object.
+ *
+ * \param enc		SES softc associated with the object.
+ * \param obj		The object to print the data for.
+ */
+static void
+ses_print_addl_data(enc_softc_t *enc, enc_element_t *obj)
+{
+	ses_element_t *elmpriv;
+	struct ses_addl_status *addl;
+	struct sbuf sesname, name, out;
+
+	elmpriv = obj->elm_private;
+	if (elmpriv == NULL)
+		return;
+
+	addl = &(elmpriv->addl);
+	if (addl->hdr == NULL)
+		return;
+
+	sbuf_new(&sesname, NULL, 16, SBUF_AUTOEXTEND);
+	sbuf_new(&name, NULL, 16, SBUF_AUTOEXTEND);
+	sbuf_new(&out, NULL, 512, SBUF_AUTOEXTEND);
+	ses_paths_iter(enc, obj, ses_elmdevname_callback, &name);
+	if (sbuf_len(&name) == 0)
+		sbuf_printf(&name, "(none)");
+	sbuf_finish(&name);
+	sbuf_printf(&sesname, "%s%d", enc->periph->periph_name,
+	    enc->periph->unit_number);
+	sbuf_finish(&sesname);
+	if (elmpriv->descr != NULL)
+		sbuf_printf(&out, "%s: %s: Element descriptor: '%s'\n",
+		    sbuf_data(&sesname), sbuf_data(&name), elmpriv->descr);
+	switch(ses_elm_addlstatus_proto(addl->hdr)) {
+	case SPSP_PROTO_SAS:
+		switch(ses_elm_sas_descr_type(addl->proto_hdr.sas)) {
+		case SES_SASOBJ_TYPE_SLOT:
+			ses_print_addl_data_sas_type0(sbuf_data(&sesname),
+			    &out, obj, sbuf_data(&name));
+			break;
+		case SES_SASOBJ_TYPE_OTHER:
+			ses_print_addl_data_sas_type1(enc, sbuf_data(&sesname),
+			    &out, obj, sbuf_data(&name));
+			break;
+		default:
+			break;
+		}
+		break;
+	case SPSP_PROTO_FC:	/* stubbed for now */
+		break;
+	default:
+		break;
+	}
+	sbuf_finish(&out);
+	printf("%s", sbuf_data(&out));
+	sbuf_delete(&out);
+	sbuf_delete(&name);
+	sbuf_delete(&sesname);
+}
+
+/**
+ * \brief Update the softc with the additional element status data for this
+ * 	  object, for SAS type 0 objects.
+ *
+ * \param enc		SES softc to be updated.
+ * \param buf		The additional element status response buffer.
+ * \param bufsiz	Size of the response buffer.
+ * \param eip		The EIP bit value.
+ * \param nobj		Number of objects attached to the SES softc.
+ * 
+ * \return		0 on success, errno otherwise.
+ */
+static int
+ses_get_elm_addlstatus_sas_type0(enc_softc_t *enc, enc_cache_t *enc_cache,
+				 uint8_t *buf, int bufsiz, int eip, int nobj)
+{
+	int err, offset, physz;
+	enc_element_t *obj;
+	ses_element_t *elmpriv;
+	struct ses_addl_status *addl;
+
+	err = offset = 0;
+
+	/* basic object setup */
+	obj = &(enc_cache->elm_map[nobj]);
+	elmpriv = obj->elm_private;
+	addl = &(elmpriv->addl);
+
+	addl->proto_hdr.sas = (union ses_elm_sas_hdr *)&buf[offset];
+
+	/* Don't assume this object has any phys */
+	bzero(&addl->proto_data, sizeof(addl->proto_data));
+	if (addl->proto_hdr.sas->base_hdr.num_phys == 0)
+		goto out;
+
+	/* Skip forward to the phy list */
+	if (eip)
+		offset += sizeof(struct ses_elm_sas_type0_eip_hdr);
+	else
+		offset += sizeof(struct ses_elm_sas_type0_base_hdr);
+
+	/* Make sure the phy list fits in the buffer */
+	physz = addl->proto_hdr.sas->base_hdr.num_phys;
+	physz *= sizeof(struct ses_elm_sas_device_phy);
+	if (physz > (bufsiz - offset + 4)) {
+		ENC_LOG(enc, "Element %d Device Phy List Beyond End Of Buffer\n",
+		    nobj);
+		err = EIO;
+		goto out;
+	}
+
+	/* Point to the phy list */
+	addl->proto_data.sasdev_phys =
+	    (struct ses_elm_sas_device_phy *)&buf[offset];
+
+out:
+	return (err);
+}
+
+/**
+ * \brief Update the softc with the additional element status data for this
+ * 	  object, for SAS type 1 objects.
+ *
+ * \param enc		SES softc to be updated.
+ * \param buf		The additional element status response buffer.
+ * \param bufsiz	Size of the response buffer.
+ * \param eip		The EIP bit value.
+ * \param nobj		Number of objects attached to the SES softc.
+ * 
+ * \return		0 on success, errno otherwise.
+ */
+static int
+ses_get_elm_addlstatus_sas_type1(enc_softc_t *enc, enc_cache_t *enc_cache,
+			         uint8_t *buf, int bufsiz, int eip, int nobj)
+{
+	int err, offset, physz;
+	enc_element_t *obj;
+	ses_element_t *elmpriv;
+	struct ses_addl_status *addl;
+
+	err = offset = 0;
+
+	/* basic object setup */
+	obj = &(enc_cache->elm_map[nobj]);
+	elmpriv = obj->elm_private;
+	addl = &(elmpriv->addl);
+
+	addl->proto_hdr.sas = (union ses_elm_sas_hdr *)&buf[offset];
+
+	/* Don't assume this object has any phys */
+	bzero(&addl->proto_data, sizeof(addl->proto_data));
+	if (addl->proto_hdr.sas->base_hdr.num_phys == 0)
+		goto out;
+
+	/* Process expanders differently from other type1 cases */
+	if (ses_obj_is_expander(enc, obj)) {
+		offset += sizeof(struct ses_elm_sas_type1_expander_hdr);
+		physz = addl->proto_hdr.sas->base_hdr.num_phys *
+		    sizeof(struct ses_elm_sas_expander_phy);
+		if (physz > (bufsiz - offset)) {
+			ENC_LOG(enc, "Element %d: Expander Phy List Beyond "
+			    "End Of Buffer\n", nobj);
+			err = EIO;
+			goto out;
+		}
+		addl->proto_data.sasexp_phys =
+		    (struct ses_elm_sas_expander_phy *)&buf[offset];
+	} else {
+		offset += sizeof(struct ses_elm_sas_type1_nonexpander_hdr);
+		physz = addl->proto_hdr.sas->base_hdr.num_phys *
+		    sizeof(struct ses_elm_sas_port_phy);
+		if (physz > (bufsiz - offset + 4)) {
+			ENC_LOG(enc, "Element %d: Port Phy List Beyond End "
+			    "Of Buffer\n", nobj);
+			err = EIO;
+			goto out;
+		}
+		addl->proto_data.sasport_phys =
+		    (struct ses_elm_sas_port_phy *)&buf[offset];
+	}
+
+out:
+	return (err);
+}
+
+/**
+ * \brief Update the softc with the additional element status data for this
+ * 	  object, for SAS objects.
+ *
+ * \param enc		SES softc to be updated.
+ * \param buf		The additional element status response buffer.
+ * \param bufsiz	Size of the response buffer.
+ * \param eip		The EIP bit value.
+ * \param tidx		Type index for this object.
+ * \param nobj		Number of objects attached to the SES softc.
+ * 
+ * \return		0 on success, errno otherwise.
+ */
+static int
+ses_get_elm_addlstatus_sas(enc_softc_t *enc, enc_cache_t *enc_cache,
+			   uint8_t *buf, int bufsiz, int eip, int tidx,
+			   int nobj)
+{
+	int dtype, err;
+	ses_cache_t *ses_cache;
+	union ses_elm_sas_hdr *hdr;
+
+	/* Need to be able to read the descriptor type! */
+	if (bufsiz < sizeof(union ses_elm_sas_hdr)) {
+		err = EIO;
+		goto out;
+	}
+
+	ses_cache = enc_cache->private;
+
+	hdr = (union ses_elm_sas_hdr *)buf;
+	dtype = ses_elm_sas_descr_type(hdr);
+	switch(dtype) {
+	case SES_SASOBJ_TYPE_SLOT:
+		switch(ses_cache->ses_types[tidx].hdr->etype_elm_type) {
+		case ELMTYP_DEVICE:
+		case ELMTYP_ARRAY_DEV:
+			break;
+		default:
+			ENC_LOG(enc, "Element %d has Additional Status type 0, "
+			    "invalid for SES element type 0x%x\n", nobj,
+			    ses_cache->ses_types[tidx].hdr->etype_elm_type);
+			err = ENODEV;
+			goto out;
+		}
+		err = ses_get_elm_addlstatus_sas_type0(enc, enc_cache,
+						       buf, bufsiz, eip,
+		    nobj);
+		break;
+	case SES_SASOBJ_TYPE_OTHER:
+		switch(ses_cache->ses_types[tidx].hdr->etype_elm_type) {
+		case ELMTYP_SAS_EXP:
+		case ELMTYP_SCSI_INI:
+		case ELMTYP_SCSI_TGT:
+		case ELMTYP_ESCC:
+			break;
+		default:
+			ENC_LOG(enc, "Element %d has Additional Status type 1, "
+			    "invalid for SES element type 0x%x\n", nobj,
+			    ses_cache->ses_types[tidx].hdr->etype_elm_type);
+			err = ENODEV;
+			goto out;
+		}
+		err = ses_get_elm_addlstatus_sas_type1(enc, enc_cache, buf,
+						       bufsiz, eip, nobj);
+		break;
+	default:
+		ENC_LOG(enc, "Element %d of type 0x%x has Additional Status "
+		    "of unknown type 0x%x\n", nobj,
+		    ses_cache->ses_types[tidx].hdr->etype_elm_type, dtype);
+		err = ENODEV;
+		break;
+	}
+
+out:
+	return (err);
+}
+
+static void
+ses_softc_invalidate(enc_softc_t *enc)
+{
+	ses_softc_t *ses;
+
+	ses = enc->enc_private;
+	ses_terminate_control_requests(&ses->ses_requests, ENXIO);
+}
+
+static void
+ses_softc_cleanup(enc_softc_t *enc)
+{
+
+	ses_cache_free(enc, &enc->enc_cache);
+	ses_cache_free(enc, &enc->enc_daemon_cache);
+	ENC_FREE_AND_NULL(enc->enc_private);
+	ENC_FREE_AND_NULL(enc->enc_cache.private);
+	ENC_FREE_AND_NULL(enc->enc_daemon_cache.private);
+}
+
+static int
+ses_init_enc(enc_softc_t *enc)
+{
+	return (0);
+}
+
+static int
+ses_get_enc_status(enc_softc_t *enc, int slpflag)
+{
+	/* Automatically updated, caller checks enc_cache->encstat itself */
+	return (0);
+}
+
+static int
+ses_set_enc_status(enc_softc_t *enc, uint8_t encstat, int slpflag)
+{
+	ses_control_request_t req;
+	ses_softc_t	     *ses;
+
+	ses = enc->enc_private;
+	req.elm_idx = SES_SETSTATUS_ENC_IDX;
+	req.elm_stat.comstatus = encstat & 0xf;
+	
+	TAILQ_INSERT_TAIL(&ses->ses_requests, &req, links);
+	enc_update_request(enc, SES_PROCESS_CONTROL_REQS);
+	cam_periph_sleep(enc->periph, &req, PUSER, "encstat", 0);
+
+	return (req.result);
+}
+
+static int
+ses_get_elm_status(enc_softc_t *enc, encioc_elm_status_t *elms, int slpflag)
+{
+	unsigned int i = elms->elm_idx;
+
+	memcpy(elms->cstat, &enc->enc_cache.elm_map[i].encstat, 4);
+	return (0);
+}
+
+static int
+ses_set_elm_status(enc_softc_t *enc, encioc_elm_status_t *elms, int slpflag)
+{
+	ses_control_request_t req;
+	ses_softc_t	     *ses;
+
+	/* If this is clear, we don't do diddly.  */
+	if ((elms->cstat[0] & SESCTL_CSEL) == 0)
+		return (0);
+
+	ses = enc->enc_private;
+	req.elm_idx = elms->elm_idx;
+	memcpy(&req.elm_stat, elms->cstat, sizeof(req.elm_stat));
+
+	TAILQ_INSERT_TAIL(&ses->ses_requests, &req, links);
+	enc_update_request(enc, SES_PROCESS_CONTROL_REQS);
+	cam_periph_sleep(enc->periph, &req, PUSER, "encstat", 0);
+
+	return (req.result);
+}
+
+static int
+ses_get_elm_desc(enc_softc_t *enc, encioc_elm_desc_t *elmd)
+{
+	int i = (int)elmd->elm_idx;
+	ses_element_t *elmpriv;
+
+	/* Assume caller has already checked obj_id validity */
+	elmpriv = enc->enc_cache.elm_map[i].elm_private;
+	/* object might not have a descriptor */
+	if (elmpriv == NULL || elmpriv->descr == NULL) {
+		elmd->elm_desc_len = 0;
+		return (0);
+	}
+	if (elmd->elm_desc_len > elmpriv->descr_len)
+		elmd->elm_desc_len = elmpriv->descr_len;
+	copyout(elmpriv->descr, elmd->elm_desc_str, elmd->elm_desc_len);
+	return (0);
+}
+
+/**
+ * \brief Respond to ENCIOC_GETELMDEVNAME, providing a device name for the
+ *	  given object id if one is available.
+ *
+ * \param enc	SES softc to examine.
+ * \param objdn	ioctl structure to read/write device name info.
+ *
+ * \return	0 on success, errno otherwise.
+ */
+static int
+ses_get_elm_devnames(enc_softc_t *enc, encioc_elm_devnames_t *elmdn)
+{
+	struct sbuf sb;
+	int len;
+
+	len = elmdn->elm_names_size;
+	if (len < 0)
+		return (EINVAL);
+
+	sbuf_new(&sb, elmdn->elm_devnames, len, 0);
+
+	cam_periph_unlock(enc->periph);
+	ses_paths_iter(enc, &enc->enc_cache.elm_map[elmdn->elm_idx],
+		       ses_elmdevname_callback, &sb);
+	sbuf_finish(&sb);
+	elmdn->elm_names_len = sbuf_len(&sb);
+	cam_periph_lock(enc->periph);
+	return (elmdn->elm_names_len > 0 ? 0 : ENODEV);
+}
+
+/**
+ * \brief Send a string to the primary subenclosure using the String Out
+ * 	  SES diagnostic page.
+ *
+ * \param enc	SES enclosure to run the command on.
+ * \param sstr	SES string structure to operate on
+ * \param ioc	Ioctl being performed
+ *
+ * \return	0 on success, errno otherwise.
+ */
+static int
+ses_handle_string(enc_softc_t *enc, encioc_string_t *sstr, int ioc)
+{
+	int amt, payload, ret;
+	char cdb[6];
+	uint8_t *buf;
+
+	/* Implement SES2r20 6.1.6 */
+	if (sstr->bufsiz > 0xffff)
+		return (EINVAL); /* buffer size too large */
+
+	if (ioc == ENCIOC_SETSTRING) {
+		payload = sstr->bufsiz + 4; /* header for SEND DIAGNOSTIC */
+		amt = 0 - payload;
+		buf = ENC_MALLOC(payload);
+		if (buf == NULL)
+			return ENOMEM;
+
+		ses_page_cdb(cdb, payload, 0, CAM_DIR_OUT);
+		/* Construct the page request */
+		buf[0] = SesStringOut;
+		buf[1] = 0;
+		buf[2] = sstr->bufsiz >> 8;
+		buf[3] = sstr->bufsiz & 0xff;
+		memcpy(&buf[4], sstr->buf, sstr->bufsiz);
+	} else if (ioc == ENCIOC_GETSTRING) {
+		payload = sstr->bufsiz;
+		amt = payload;
+		ses_page_cdb(cdb, payload, SesStringIn, CAM_DIR_IN);
+		buf = sstr->buf;
+	} else
+		return EINVAL;
+
+	ret = enc_runcmd(enc, cdb, 6, buf, &amt);
+	if (ioc == ENCIOC_SETSTRING)
+		ENC_FREE(buf);
+	return ret;
+}
+
+/**
+ * \invariant Called with cam_periph mutex held.
+ */
+static void
+ses_poll_status(enc_softc_t *enc)
+{
+	ses_softc_t *ses;
+
+	ses = enc->enc_private;
+	enc_update_request(enc, SES_UPDATE_GETSTATUS);
+	if (ses->ses_flags & SES_FLAG_ADDLSTATUS)
+		enc_update_request(enc, SES_UPDATE_GETELMADDLSTATUS);
+}
+
+/**
+ * \brief Notification received when CAM detects a new device in the
+ *        SCSI domain in which this SEP resides.
+ *
+ * \param enc	SES enclosure instance.
+ */
+static void
+ses_device_found(enc_softc_t *enc)
+{
+	ses_poll_status(enc);
+	enc_update_request(enc, SES_PUBLISH_PHYSPATHS);
+}
+
+static struct enc_vec ses_enc_vec =
+{
+	.softc_invalidate	= ses_softc_invalidate,
+	.softc_cleanup		= ses_softc_cleanup,
+	.init_enc		= ses_init_enc,
+	.get_enc_status		= ses_get_enc_status,
+	.set_enc_status		= ses_set_enc_status,
+	.get_elm_status		= ses_get_elm_status,
+	.set_elm_status		= ses_set_elm_status,
+	.get_elm_desc		= ses_get_elm_desc,
+	.get_elm_devnames	= ses_get_elm_devnames,
+	.handle_string		= ses_handle_string,
+	.device_found		= ses_device_found,
+	.poll_status		= ses_poll_status
+};
+
+/**
+ * \brief Initialize a new SES instance.
+ *
+ * \param enc		SES softc structure to set up the instance in.
+ * \param doinit	Do the initialization (see main driver).
+ *
+ * \return		0 on success, errno otherwise.
+ */
+int
+ses_softc_init(enc_softc_t *enc)
+{
+	ses_softc_t *ses_softc;
+
+	CAM_DEBUG(enc->periph->path, CAM_DEBUG_SUBTRACE,
+	    ("entering enc_softc_init(%p)\n", enc));
+
+	enc->enc_vec = ses_enc_vec;
+	enc->enc_fsm_states = enc_fsm_states;
+
+	if (enc->enc_private == NULL)
+		enc->enc_private = ENC_MALLOCZ(sizeof(ses_softc_t));
+	if (enc->enc_cache.private == NULL)
+		enc->enc_cache.private = ENC_MALLOCZ(sizeof(ses_cache_t));
+	if (enc->enc_daemon_cache.private == NULL)
+		enc->enc_daemon_cache.private =
+		     ENC_MALLOCZ(sizeof(ses_cache_t));
+
+	if (enc->enc_private == NULL
+	 || enc->enc_cache.private == NULL
+	 || enc->enc_daemon_cache.private == NULL) {
+		ENC_FREE_AND_NULL(enc->enc_private);
+		ENC_FREE_AND_NULL(enc->enc_cache.private);
+		ENC_FREE_AND_NULL(enc->enc_daemon_cache.private);
+		return (ENOMEM);
+	}
+
+	ses_softc = enc->enc_private;
+	TAILQ_INIT(&ses_softc->ses_requests);
+	TAILQ_INIT(&ses_softc->ses_pending_requests);
+
+	enc_update_request(enc, SES_UPDATE_PAGES);
+
+	// XXX: Move this to the FSM so it doesn't hang init
+	if (0) (void) ses_set_timed_completion(enc, 1);
+
+	return (0);
+}
+
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/scsi/scsi_pass.c
--- a/head/sys/cam/scsi/scsi_pass.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/scsi/scsi_pass.c	Wed Jul 25 16:45:04 2012 +0300
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_pass.c 223089 2011-06-14 17:10:32Z gibbs $");
+__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_pass.c 237328 2012-06-20 17:08:00Z ken $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -55,7 +55,8 @@
 typedef enum {
 	PASS_FLAG_OPEN			= 0x01,
 	PASS_FLAG_LOCKED		= 0x02,
-	PASS_FLAG_INVALID		= 0x04
+	PASS_FLAG_INVALID		= 0x04,
+	PASS_FLAG_INITIAL_PHYSPATH	= 0x08
 } pass_flags;
 
 typedef enum {
@@ -111,7 +112,7 @@
 
 static struct cdevsw pass_cdevsw = {
 	.d_version =	D_VERSION,
-	.d_flags =	0,
+	.d_flags =	D_TRACKCLOSE,
 	.d_open =	passopen,
 	.d_close =	passclose,
 	.d_ioctl =	passioctl,
@@ -133,7 +134,18 @@
 		printf("pass: Failed to attach master async callback "
 		       "due to status 0x%x!\n", status);
 	}
-	
+
+}
+
+static void
+passdevgonecb(void *arg)
+{
+	struct cam_periph *periph;
+
+	periph = (struct cam_periph *)arg;
+
+	xpt_print(periph->path, "%s: devfs entry is gone\n", __func__);
+	cam_periph_release(periph);
 }
 
 static void
@@ -151,6 +163,12 @@
 	softc->flags |= PASS_FLAG_INVALID;
 
 	/*
+	 * Tell devfs this device has gone away, and ask for a callback
+	 * when it has cleaned up its state.
+	 */
+	destroy_dev_sched_cb(softc->dev, passdevgonecb, periph);
+
+	/*
 	 * XXX Return all queued I/O with ENXIO.
 	 * XXX Handle any transactions queued to the card
 	 *     with XPT_ABORT_CCB.
@@ -176,11 +194,6 @@
 	cam_periph_unlock(periph);
 	taskqueue_drain(taskqueue_thread, &softc->add_physpath_task);
 
-	/*
-	 * passcleanup() is indirectly a d_close method via passclose,
-	 * so using destroy_dev(9) directly can result in deadlock.
-	 */
-	destroy_dev_sched(softc->dev);
 	cam_periph_lock(periph);
 
 	free(softc, M_DEVBUF);
@@ -199,6 +212,12 @@
 	 */
 	periph = context;
 	softc = periph->softc;
+	cam_periph_lock(periph);
+	if (periph->flags & CAM_PERIPH_INVALID) {
+		cam_periph_unlock(periph);
+		return;
+	}
+	cam_periph_unlock(periph);
 	physpath = malloc(MAXPATHLEN, M_DEVBUF, M_WAITOK);
 	if (xpt_getattr(physpath, MAXPATHLEN,
 			"GEOM::physpath", periph->path) == 0
@@ -208,6 +227,19 @@
 					softc->dev, softc->alias_dev, physpath);
 	}
 	free(physpath, M_DEVBUF);
+
+	/*
+	 * Now that we've made our alias, we no longer have to have a
+	 * reference to the device.
+	 */
+	cam_periph_lock(periph);
+	if ((softc->flags & PASS_FLAG_INITIAL_PHYSPATH) == 0) {
+		softc->flags |= PASS_FLAG_INITIAL_PHYSPATH;
+		cam_periph_unlock(periph);
+		dev_rel(softc->dev);
+	}
+	else
+		cam_periph_unlock(periph);
 }
 
 static void
@@ -281,12 +313,12 @@
 
 	cgd = (struct ccb_getdev *)arg;
 	if (periph == NULL) {
-		printf("passregister: periph was NULL!!\n");
+		printf("%s: periph was NULL!!\n", __func__);
 		return(CAM_REQ_CMP_ERR);
 	}
 
 	if (cgd == NULL) {
-		printf("passregister: no getdev CCB, can't register device\n");
+		printf("%s: no getdev CCB, can't register device\n", __func__);
 		return(CAM_REQ_CMP_ERR);
 	}
 
@@ -294,8 +326,8 @@
 					    M_DEVBUF, M_NOWAIT);
 
 	if (softc == NULL) {
-		printf("passregister: Unable to probe new device. "
-		       "Unable to allocate softc\n");				
+		printf("%s: Unable to probe new device. "
+		       "Unable to allocate softc\n", __func__);
 		return(CAM_REQ_CMP_ERR);
 	}
 
@@ -331,10 +363,31 @@
 			  DEVSTAT_TYPE_PASS,
 			  DEVSTAT_PRIORITY_PASS);
 
+	/*
+	 * Acquire a reference to the periph before we create the devfs
+	 * instance for it.  We'll release this reference once the devfs
+	 * instance has been freed.
+	 */
+	if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
+		xpt_print(periph->path, "%s: lost periph during "
+			  "registration!\n", __func__);
+		mtx_lock(periph->sim->mtx);
+		return (CAM_REQ_CMP_ERR);
+	}
+
 	/* Register the device */
 	softc->dev = make_dev(&pass_cdevsw, periph->unit_number,
 			      UID_ROOT, GID_OPERATOR, 0600, "%s%d",
 			      periph->periph_name, periph->unit_number);
+
+	/*
+	 * Now that we have made the devfs instance, hold a reference to it
+	 * until the task queue has run to setup the physical path alias.
+	 * That way devfs won't get rid of the device before we add our
+	 * alias.
+	 */
+	dev_ref(softc->dev);
+
 	mtx_lock(periph->sim->mtx);
 	softc->dev->si_drv1 = periph;
 
@@ -377,8 +430,8 @@
 	softc = (struct pass_softc *)periph->softc;
 
 	if (softc->flags & PASS_FLAG_INVALID) {
+		cam_periph_release_locked(periph);
 		cam_periph_unlock(periph);
-		cam_periph_release(periph);
 		return(ENXIO);
 	}
 
@@ -387,8 +440,8 @@
 	 */
 	error = securelevel_gt(td->td_ucred, 1);
 	if (error) {
+		cam_periph_release_locked(periph);
 		cam_periph_unlock(periph);
-		cam_periph_release(periph);
 		return(error);
 	}
 
@@ -396,8 +449,8 @@
 	 * Only allow read-write access.
 	 */
 	if (((flags & FWRITE) == 0) || ((flags & FREAD) == 0)) {
+		cam_periph_release_locked(periph);
 		cam_periph_unlock(periph);
-		cam_periph_release(periph);
 		return(EPERM);
 	}
 
@@ -406,19 +459,12 @@
 	 */
 	if ((flags & O_NONBLOCK) != 0) {
 		xpt_print(periph->path, "can't do nonblocking access\n");
+		cam_periph_release_locked(periph);
 		cam_periph_unlock(periph);
-		cam_periph_release(periph);
 		return(EINVAL);
 	}
 
-	if ((softc->flags & PASS_FLAG_OPEN) == 0) {
-		softc->flags |= PASS_FLAG_OPEN;
-		cam_periph_unlock(periph);
-	} else {
-		/* Device closes aren't symmertical, so fix up the refcount */
-		cam_periph_unlock(periph);
-		cam_periph_release(periph);
-	}
+	cam_periph_unlock(periph);
 
 	return (error);
 }
@@ -427,18 +473,11 @@
 passclose(struct cdev *dev, int flag, int fmt, struct thread *td)
 {
 	struct 	cam_periph *periph;
-	struct	pass_softc *softc;
 
 	periph = (struct cam_periph *)dev->si_drv1;
 	if (periph == NULL)
 		return (ENXIO);	
 
-	cam_periph_lock(periph);
-
-	softc = (struct pass_softc *)periph->softc;
-	softc->flags &= ~PASS_FLAG_OPEN;
-
-	cam_periph_unlock(periph);
 	cam_periph_release(periph);
 
 	return (0);
@@ -638,9 +677,9 @@
 	 * that request.  Otherwise, it's up to the user to perform any
 	 * error recovery.
 	 */
-	cam_periph_runccb(ccb,
-	    (ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ? passerror : NULL,
-	    /* cam_flags */ CAM_RETRY_SELTO, /* sense_flags */SF_RETRY_UA,
+	cam_periph_runccb(ccb, passerror, /* cam_flags */ CAM_RETRY_SELTO,
+	    /* sense_flags */ ((ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ?
+	     SF_RETRY_UA : SF_NO_RECOVERY) | SF_NO_PRINT,
 	    softc->device_stats);
 
 	if (need_unmap != 0)
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/scsi/scsi_pt.c
--- a/head/sys/cam/scsi/scsi_pt.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/scsi/scsi_pt.c	Wed Jul 25 16:45:04 2012 +0300
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_pt.c 220644 2011-04-14 21:25:32Z mav $");
+__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_pt.c 236602 2012-06-05 09:45:42Z mav $");
 
 #include <sys/param.h>
 #include <sys/queue.h>
@@ -148,8 +148,8 @@
 
 	cam_periph_lock(periph);
 	if (softc->flags & PT_FLAG_DEVICE_INVALID) {
+		cam_periph_release_locked(periph);
 		cam_periph_unlock(periph);
-		cam_periph_release(periph);
 		return(ENXIO);
 	}
 
@@ -182,8 +182,8 @@
 	cam_periph_lock(periph);
 
 	softc->flags &= ~PT_FLAG_OPEN;
+	cam_periph_release_locked(periph);
 	cam_periph_unlock(periph);
-	cam_periph_release(periph);
 	return (0);
 }
 
@@ -425,12 +425,14 @@
 
 	softc = (struct pt_softc *)periph->softc;
 
+	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("ptstart\n"));
+
 	/*
 	 * See if there is a buf with work for us to do..
 	 */
 	bp = bioq_first(&softc->bio_queue);
 	if (periph->immediate_priority <= periph->pinfo.priority) {
-		CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE,
+		CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
 				("queuing for immediate ccb\n"));
 		start_ccb->ccb_h.ccb_state = PT_CCB_WAITING;
 		SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
@@ -483,6 +485,9 @@
 	struct ccb_scsiio *csio;
 
 	softc = (struct pt_softc *)periph->softc;
+
+	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("ptdone\n"));
+
 	csio = &done_ccb->csio;
 	switch (csio->ccb_h.ccb_state) {
 	case PT_CCB_BUFFER_IO:
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/scsi/scsi_sa.c
--- a/head/sys/cam/scsi/scsi_sa.c	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/scsi/scsi_sa.c	Wed Jul 25 16:45:04 2012 +0300
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_sa.c 229288 2012-01-02 17:02:45Z mav $");
+__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_sa.c 236712 2012-06-07 10:05:51Z mav $");
 
 #include <sys/param.h>
 #include <sys/queue.h>
@@ -1482,10 +1482,6 @@
 		softc->quirks = ((struct sa_quirk_entry *)match)->quirks;
 		softc->last_media_blksize =
 		    ((struct sa_quirk_entry *)match)->prefblk;
-#ifdef	CAMDEBUG
-		xpt_print(periph->path, "found quirk entry %d\n",
-		    (int) (((struct sa_quirk_entry *) match) - sa_quirk_table));
-#endif
 	} else
 		softc->quirks = SA_QUIRK_NONE;
 
@@ -1798,13 +1794,11 @@
 		 */
 		if (error || (softc->flags & SA_FLAG_ERR_PENDING))
 			cam_release_devq(done_ccb->ccb_h.path, 0, 0, 0, 0);
-#ifdef	CAMDEBUG
 		if (error || bp->bio_resid) {
 			CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
 			    	  ("error %d resid %ld count %ld\n", error,
 				  bp->bio_resid, bp->bio_bcount));
 		}
-#endif
 		biofinish(bp, softc->device_stats, 0);
 		break;
 	}
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/scsi/scsi_ses.c
--- a/head/sys/cam/scsi/scsi_ses.c	Wed Jul 25 16:42:35 2012 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2533 +0,0 @@
-/*-
- * Copyright (c) 2000 Matthew Jacob
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification, immediately at the beginning of the file.
- * 2. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_ses.c 229288 2012-01-02 17:02:45Z mav $");
-
-#include <sys/param.h>
-#include <sys/queue.h>
-#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/types.h>
-#include <sys/malloc.h>
-#include <sys/fcntl.h>
-#include <sys/conf.h>
-#include <sys/errno.h>
-#include <machine/stdarg.h>
-
-#include <cam/cam.h>
-#include <cam/cam_ccb.h>
-#include <cam/cam_periph.h>
-#include <cam/cam_xpt_periph.h>
-#include <cam/cam_debug.h>
-#include <cam/cam_sim.h>
-
-#include <cam/scsi/scsi_all.h>
-#include <cam/scsi/scsi_message.h>
-#include <sys/ioccom.h>
-#include <cam/scsi/scsi_ses.h>
-
-#include <opt_ses.h>
-
-static MALLOC_DEFINE(M_SCSISES, "SCSI SES", "SCSI SES buffers");
-
-/*
- * Platform Independent Driver Internal Definitions for SES devices.
- */
-typedef enum {
-	SES_NONE,
-	SES_SES_SCSI2,
-	SES_SES,
-	SES_SES_PASSTHROUGH,
-	SES_SEN,
-	SES_SAFT
-} enctyp;
-
-struct ses_softc;
-typedef struct ses_softc ses_softc_t;
-typedef struct {
-	int (*softc_init)(ses_softc_t *, int);
-	int (*init_enc)(ses_softc_t *);
-	int (*get_encstat)(ses_softc_t *, int);
-	int (*set_encstat)(ses_softc_t *, ses_encstat, int);
-	int (*get_objstat)(ses_softc_t *, ses_objstat *, int);
-	int (*set_objstat)(ses_softc_t *, ses_objstat *, int);
-} encvec;
-
-#define	ENCI_SVALID	0x80
-
-typedef struct {
-	uint32_t
-		enctype	: 8,		/* enclosure type */
-		subenclosure : 8,	/* subenclosure id */
-		svalid	: 1,		/* enclosure information valid */
-		priv	: 15;		/* private data, per object */
-	uint8_t	encstat[4];	/* state && stats */
-} encobj;
-
-#define	SEN_ID		"UNISYS           SUN_SEN"
-#define	SEN_ID_LEN	24
-
-
-static enctyp ses_type(void *, int);
-
-
-/* Forward reference to Enclosure Functions */
-static int ses_softc_init(ses_softc_t *, int);
-static int ses_init_enc(ses_softc_t *);
-static int ses_get_encstat(ses_softc_t *, int);
-static int ses_set_encstat(ses_softc_t *, uint8_t, int);
-static int ses_get_objstat(ses_softc_t *, ses_objstat *, int);
-static int ses_set_objstat(ses_softc_t *, ses_objstat *, int);
-
-static int safte_softc_init(ses_softc_t *, int);
-static int safte_init_enc(ses_softc_t *);
-static int safte_get_encstat(ses_softc_t *, int);
-static int safte_set_encstat(ses_softc_t *, uint8_t, int);
-static int safte_get_objstat(ses_softc_t *, ses_objstat *, int);
-static int safte_set_objstat(ses_softc_t *, ses_objstat *, int);
-
-/*
- * Platform implementation defines/functions for SES internal kernel stuff
- */
-
-#define	STRNCMP			strncmp
-#define	PRINTF			printf
-#define	SES_LOG			ses_log
-#ifdef	DEBUG
-#define	SES_DLOG		ses_log
-#else
-#define	SES_DLOG		if (0) ses_log
-#endif
-#define	SES_VLOG		if (bootverbose) ses_log
-#define	SES_MALLOC(amt)		malloc(amt, M_SCSISES, M_NOWAIT)
-#define	SES_FREE(ptr, amt)	free(ptr, M_SCSISES)
-#define	MEMZERO			bzero
-#define	MEMCPY(dest, src, amt)	bcopy(src, dest, amt)
-
-static int ses_runcmd(struct ses_softc *, char *, int, char *, int *);
-static void ses_log(struct ses_softc *, const char *, ...);
-
-/*
- * Gerenal FreeBSD kernel stuff.
- */
-
-
-#define ccb_state	ppriv_field0
-#define ccb_bp		ppriv_ptr1
-
-struct ses_softc {
-	enctyp		ses_type;	/* type of enclosure */
-	encvec		ses_vec;	/* vector to handlers */
-	void *		ses_private;	/* per-type private data */
-	encobj *	ses_objmap;	/* objects */
-	uint32_t	ses_nobjects;	/* number of objects */
-	ses_encstat	ses_encstat;	/* overall status */
-	uint8_t	ses_flags;
-	union ccb	ses_saved_ccb;
-	struct cdev *ses_dev;
-	struct cam_periph *periph;
-};
-#define	SES_FLAG_INVALID	0x01
-#define	SES_FLAG_OPEN		0x02
-#define	SES_FLAG_INITIALIZED	0x04
-
-static	d_open_t	sesopen;
-static	d_close_t	sesclose;
-static	d_ioctl_t	sesioctl;
-static	periph_init_t	sesinit;
-static  periph_ctor_t	sesregister;
-static	periph_oninv_t	sesoninvalidate;
-static  periph_dtor_t   sescleanup;
-static  periph_start_t  sesstart;
-
-static void sesasync(void *, uint32_t, struct cam_path *, void *);
-static void sesdone(struct cam_periph *, union ccb *);
-static int seserror(union ccb *, uint32_t, uint32_t);
-
-static struct periph_driver sesdriver = {
-	sesinit, "ses",
-	TAILQ_HEAD_INITIALIZER(sesdriver.units), /* generation */ 0
-};
-
-PERIPHDRIVER_DECLARE(ses, sesdriver);
-
-static struct cdevsw ses_cdevsw = {
-	.d_version =	D_VERSION,
-	.d_open =	sesopen,
-	.d_close =	sesclose,
-	.d_ioctl =	sesioctl,
-	.d_name =	"ses",
-	.d_flags =	0,
-};
-
-static void
-sesinit(void)
-{
-	cam_status status;
-
-	/*
-	 * Install a global async callback.  This callback will
-	 * receive async callbacks like "new device found".
-	 */
-	status = xpt_register_async(AC_FOUND_DEVICE, sesasync, NULL, NULL);
-
-	if (status != CAM_REQ_CMP) {
-		printf("ses: Failed to attach master async callback "
-		       "due to status 0x%x!\n", status);
-	}
-}
-
-static void
-sesoninvalidate(struct cam_periph *periph)
-{
-	struct ses_softc *softc;
-
-	softc = (struct ses_softc *)periph->softc;
-
-	/*
-	 * Unregister any async callbacks.
-	 */
-	xpt_register_async(0, sesasync, periph, periph->path);
-
-	softc->ses_flags |= SES_FLAG_INVALID;
-
-	xpt_print(periph->path, "lost device\n");
-}
-
-static void
-sescleanup(struct cam_periph *periph)
-{
-	struct ses_softc *softc;
-
-	softc = (struct ses_softc *)periph->softc;
-
-	xpt_print(periph->path, "removing device entry\n");
-	cam_periph_unlock(periph);
-	destroy_dev(softc->ses_dev);
-	cam_periph_lock(periph);
-	free(softc, M_SCSISES);
-}
-
-static void
-sesasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
-{
-	struct cam_periph *periph;
-
-	periph = (struct cam_periph *)callback_arg;
-
-	switch(code) {
-	case AC_FOUND_DEVICE:
-	{
-		cam_status status;
-		struct ccb_getdev *cgd;
-		int inq_len;
-
-		cgd = (struct ccb_getdev *)arg;
-		if (arg == NULL) {
-			break;
-		}
-
-		if (cgd->protocol != PROTO_SCSI)
-			break;
-
-		inq_len = cgd->inq_data.additional_length + 4;
-
-		/*
-		 * PROBLEM: WE NEED TO LOOK AT BYTES 48-53 TO SEE IF THIS IS
-		 * PROBLEM: IS A SAF-TE DEVICE.
-		 */
-		switch (ses_type(&cgd->inq_data, inq_len)) {
-		case SES_SES:
-		case SES_SES_SCSI2:
-		case SES_SES_PASSTHROUGH:
-		case SES_SEN:
-		case SES_SAFT:
-			break;
-		default:
-			return;
-		}
-
-		status = cam_periph_alloc(sesregister, sesoninvalidate,
-		    sescleanup, sesstart, "ses", CAM_PERIPH_BIO,
-		    cgd->ccb_h.path, sesasync, AC_FOUND_DEVICE, cgd);
-
-		if (status != CAM_REQ_CMP && status != CAM_REQ_INPROG) {
-			printf("sesasync: Unable to probe new device due to "
-			    "status 0x%x\n", status);
-		}
-		break;
-	}
-	default:
-		cam_periph_async(periph, code, path, arg);
-		break;
-	}
-}
-
-static cam_status
-sesregister(struct cam_periph *periph, void *arg)
-{
-	struct ses_softc *softc;
-	struct ccb_getdev *cgd;
-	char *tname;
-
-	cgd = (struct ccb_getdev *)arg;
-	if (periph == NULL) {
-		printf("sesregister: periph was NULL!!\n");
-		return (CAM_REQ_CMP_ERR);
-	}
-
-	if (cgd == NULL) {
-		printf("sesregister: no getdev CCB, can't register device\n");
-		return (CAM_REQ_CMP_ERR);
-	}
-
-	softc = SES_MALLOC(sizeof (struct ses_softc));
-	if (softc == NULL) {
-		printf("sesregister: Unable to probe new device. "
-		       "Unable to allocate softc\n");				
-		return (CAM_REQ_CMP_ERR);
-	}
-	bzero(softc, sizeof (struct ses_softc));
-	periph->softc = softc;
-	softc->periph = periph;
-
-	softc->ses_type = ses_type(&cgd->inq_data, sizeof (cgd->inq_data));
-
-	switch (softc->ses_type) {
-	case SES_SES:
-	case SES_SES_SCSI2:
-        case SES_SES_PASSTHROUGH:
-		softc->ses_vec.softc_init = ses_softc_init;
-		softc->ses_vec.init_enc = ses_init_enc;
-		softc->ses_vec.get_encstat = ses_get_encstat;
-		softc->ses_vec.set_encstat = ses_set_encstat;
-		softc->ses_vec.get_objstat = ses_get_objstat;
-		softc->ses_vec.set_objstat = ses_set_objstat;
-		break;
-        case SES_SAFT:
-		softc->ses_vec.softc_init = safte_softc_init;
-		softc->ses_vec.init_enc = safte_init_enc;
-		softc->ses_vec.get_encstat = safte_get_encstat;
-		softc->ses_vec.set_encstat = safte_set_encstat;
-		softc->ses_vec.get_objstat = safte_get_objstat;
-		softc->ses_vec.set_objstat = safte_set_objstat;
-		break;
-        case SES_SEN:
-		break;
-	case SES_NONE:
-	default:
-		free(softc, M_SCSISES);
-		return (CAM_REQ_CMP_ERR);
-	}
-
-	cam_periph_unlock(periph);
-	softc->ses_dev = make_dev(&ses_cdevsw, periph->unit_number,
-	    UID_ROOT, GID_OPERATOR, 0600, "%s%d",
-	    periph->periph_name, periph->unit_number);
-	cam_periph_lock(periph);
-	softc->ses_dev->si_drv1 = periph;
-
-	/*
-	 * Add an async callback so that we get
-	 * notified if this device goes away.
-	 */
-	xpt_register_async(AC_LOST_DEVICE, sesasync, periph, periph->path);
-
-	switch (softc->ses_type) {
-	default:
-	case SES_NONE:
-		tname = "No SES device";
-		break;
-	case SES_SES_SCSI2:
-		tname = "SCSI-2 SES Device";
-		break;
-	case SES_SES:
-		tname = "SCSI-3 SES Device";
-		break;
-        case SES_SES_PASSTHROUGH:
-		tname = "SES Passthrough Device";
-		break;
-        case SES_SEN:
-		tname = "UNISYS SEN Device (NOT HANDLED YET)";
-		break;
-        case SES_SAFT:
-		tname = "SAF-TE Compliant Device";
-		break;
-	}
-	xpt_announce_periph(periph, tname);
-	return (CAM_REQ_CMP);
-}
-
-static int
-sesopen(struct cdev *dev, int flags, int fmt, struct thread *td)
-{
-	struct cam_periph *periph;
-	struct ses_softc *softc;
-	int error = 0;
-
-	periph = (struct cam_periph *)dev->si_drv1;
-	if (periph == NULL) {
-		return (ENXIO);
-	}
-
-	if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
-		cam_periph_unlock(periph);
-		return (ENXIO);
-	}
-
-	cam_periph_lock(periph);
-
-	softc = (struct ses_softc *)periph->softc;
-
-	if (softc->ses_flags & SES_FLAG_INVALID) {
-		error = ENXIO;
-		goto out;
-	}
-	if (softc->ses_flags & SES_FLAG_OPEN) {
-		error = EBUSY;
-		goto out;
-	}
-	if (softc->ses_vec.softc_init == NULL) {
-		error = ENXIO;
-		goto out;
-	}
-
-	softc->ses_flags |= SES_FLAG_OPEN;
-	if ((softc->ses_flags & SES_FLAG_INITIALIZED) == 0) {
-		error = (*softc->ses_vec.softc_init)(softc, 1);
-		if (error)
-			softc->ses_flags &= ~SES_FLAG_OPEN;
-		else
-			softc->ses_flags |= SES_FLAG_INITIALIZED;
-	}
-
-out:
-	cam_periph_unlock(periph);
-	if (error) {
-		cam_periph_release(periph);
-	}
-	return (error);
-}
-
-static int
-sesclose(struct cdev *dev, int flag, int fmt, struct thread *td)
-{
-	struct cam_periph *periph;
-	struct ses_softc *softc;
-	int error;
-
-	error = 0;
-
-	periph = (struct cam_periph *)dev->si_drv1;
-	if (periph == NULL)
-		return (ENXIO);
-
-	cam_periph_lock(periph);
-
-	softc = (struct ses_softc *)periph->softc;
-	softc->ses_flags &= ~SES_FLAG_OPEN;
-
-	cam_periph_unlock(periph);
-	cam_periph_release(periph);
-
-	return (0);
-}
-
-static void
-sesstart(struct cam_periph *p, union ccb *sccb)
-{
-	if (p->immediate_priority <= p->pinfo.priority) {
-		SLIST_INSERT_HEAD(&p->ccb_list, &sccb->ccb_h, periph_links.sle);
-		p->immediate_priority = CAM_PRIORITY_NONE;
-		wakeup(&p->ccb_list);
-	}
-}
-
-static void
-sesdone(struct cam_periph *periph, union ccb *dccb)
-{
-	wakeup(&dccb->ccb_h.cbfcnp);
-}
-
-static int
-seserror(union ccb *ccb, uint32_t cflags, uint32_t sflags)
-{
-	struct ses_softc *softc;
-	struct cam_periph *periph;
-
-	periph = xpt_path_periph(ccb->ccb_h.path);
-	softc = (struct ses_softc *)periph->softc;
-
-	return (cam_periph_error(ccb, cflags, sflags, &softc->ses_saved_ccb));
-}
-
-static int
-sesioctl(struct cdev *dev, u_long cmd, caddr_t arg_addr, int flag, struct thread *td)
-{
-	struct cam_periph *periph;
-	ses_encstat tmp;
-	ses_objstat objs;
-	ses_object *uobj;
-	struct ses_softc *ssc;
-	void *addr;
-	int error, i;
-
-
-	if (arg_addr)
-		addr = *((caddr_t *) arg_addr);
-	else
-		addr = NULL;
-
-	periph = (struct cam_periph *)dev->si_drv1;
-	if (periph == NULL)
-		return (ENXIO);
-
-	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering sesioctl\n"));
-
-	cam_periph_lock(periph);
-	ssc = (struct ses_softc *)periph->softc;
-
-	/*
-	 * Now check to see whether we're initialized or not.
-	 * This actually should never fail as we're not supposed
-	 * to get past ses_open w/o successfully initializing
-	 * things.
-	 */
-	if ((ssc->ses_flags & SES_FLAG_INITIALIZED) == 0) {
-		cam_periph_unlock(periph);
-		return (ENXIO);
-	}
-	cam_periph_unlock(periph);
-
-	error = 0;
-
-	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
-	    ("trying to do ioctl %#lx\n", cmd));
-
-	/*
-	 * If this command can change the device's state,
-	 * we must have the device open for writing.
-	 *
-	 * For commands that get information about the
-	 * device- we don't need to lock the peripheral
-	 * if we aren't running a command. The number
-	 * of objects and the contents will stay stable
-	 * after the first open that does initialization.
-	 * The periph also can't go away while a user
-	 * process has it open.
-	 */
-	switch (cmd) {
-	case SESIOC_GETNOBJ:
-	case SESIOC_GETOBJMAP:
-	case SESIOC_GETENCSTAT:
-	case SESIOC_GETOBJSTAT:
-		break;
-	default:
-		if ((flag & FWRITE) == 0) {
-			return (EBADF);
-		}
-	}
-
-	switch (cmd) {
-	case SESIOC_GETNOBJ:
-		error = copyout(&ssc->ses_nobjects, addr,
-		    sizeof (ssc->ses_nobjects));
-		break;
-		
-	case SESIOC_GETOBJMAP:
-		for (uobj = addr, i = 0; i != ssc->ses_nobjects; i++) {
-			ses_object kobj;
-			kobj.obj_id = i;
-			kobj.subencid = ssc->ses_objmap[i].subenclosure;
-			kobj.object_type = ssc->ses_objmap[i].enctype;
-			error = copyout(&kobj, &uobj[i], sizeof (ses_object));
-			if (error) {
-				break;
-			}
-		}
-		break;
-
-	case SESIOC_GETENCSTAT:
-		cam_periph_lock(periph);
-		error = (*ssc->ses_vec.get_encstat)(ssc, 1);
-		if (error) {
-			cam_periph_unlock(periph);
-			break;
-		}
-		tmp = ssc->ses_encstat & ~ENCI_SVALID;
-		cam_periph_unlock(periph);
-		error = copyout(&tmp, addr, sizeof (ses_encstat));
-		ssc->ses_encstat = tmp;
-		break;
-
-	case SESIOC_SETENCSTAT:
-		error = copyin(addr, &tmp, sizeof (ses_encstat));
-		if (error)
-			break;
-		cam_periph_lock(periph);
-		error = (*ssc->ses_vec.set_encstat)(ssc, tmp, 1);
-		cam_periph_unlock(periph);
-		break;
-
-	case SESIOC_GETOBJSTAT:
-		error = copyin(addr, &objs, sizeof (ses_objstat));
-		if (error)
-			break;
-		if (objs.obj_id >= ssc->ses_nobjects) {
-			error = EINVAL;
-			break;
-		}
-		cam_periph_lock(periph);
-		error = (*ssc->ses_vec.get_objstat)(ssc, &objs, 1);
-		cam_periph_unlock(periph);
-		if (error)
-			break;
-		error = copyout(&objs, addr, sizeof (ses_objstat));
-		/*
-		 * Always (for now) invalidate entry.
-		 */
-		ssc->ses_objmap[objs.obj_id].svalid = 0;
-		break;
-
-	case SESIOC_SETOBJSTAT:
-		error = copyin(addr, &objs, sizeof (ses_objstat));
-		if (error)
-			break;
-
-		if (objs.obj_id >= ssc->ses_nobjects) {
-			error = EINVAL;
-			break;
-		}
-		cam_periph_lock(periph);
-		error = (*ssc->ses_vec.set_objstat)(ssc, &objs, 1);
-		cam_periph_unlock(periph);
-
-		/*
-		 * Always (for now) invalidate entry.
-		 */
-		ssc->ses_objmap[objs.obj_id].svalid = 0;
-		break;
-
-	case SESIOC_INIT:
-
-		cam_periph_lock(periph);
-		error = (*ssc->ses_vec.init_enc)(ssc);
-		cam_periph_unlock(periph);
-		break;
-
-	default:
-		cam_periph_lock(periph);
-		error = cam_periph_ioctl(periph, cmd, arg_addr, seserror);
-		cam_periph_unlock(periph);
-		break;
-	}
-	return (error);
-}
-
-#define	SES_CFLAGS	CAM_RETRY_SELTO
-#define	SES_FLAGS	SF_NO_PRINT | SF_RETRY_UA
-static int
-ses_runcmd(struct ses_softc *ssc, char *cdb, int cdbl, char *dptr, int *dlenp)
-{
-	int error, dlen;
-	ccb_flags ddf;
-	union ccb *ccb;
-
-	if (dptr) {
-		if ((dlen = *dlenp) < 0) {
-			dlen = -dlen;
-			ddf = CAM_DIR_OUT;
-		} else {
-			ddf = CAM_DIR_IN;
-		}
-	} else {
-		dlen = 0;
-		ddf = CAM_DIR_NONE;
-	}
-
-	if (cdbl > IOCDBLEN) {
-		cdbl = IOCDBLEN;
-	}
-
-	ccb = cam_periph_getccb(ssc->periph, 1);
-	cam_fill_csio(&ccb->csio, 0, sesdone, ddf, MSG_SIMPLE_Q_TAG, dptr,
-	    dlen, sizeof (struct scsi_sense_data), cdbl, 60 * 1000);
-	bcopy(cdb, ccb->csio.cdb_io.cdb_bytes, cdbl);
-
-	error = cam_periph_runccb(ccb, seserror, SES_CFLAGS, SES_FLAGS, NULL);
-	if (error) {
-		if (dptr) {
-			*dlenp = dlen;
-		}
-	} else {
-		if (dptr) {
-			*dlenp = ccb->csio.resid;
-		}
-	}
-	xpt_release_ccb(ccb);
-	return (error);
-}
-
-static void
-ses_log(struct ses_softc *ssc, const char *fmt, ...)
-{
-	va_list ap;
-
-	printf("%s%d: ", ssc->periph->periph_name, ssc->periph->unit_number);
-	va_start(ap, fmt);
-	vprintf(fmt, ap);
-	va_end(ap);
-}
-
-/*
- * The code after this point runs on many platforms,
- * so forgive the slightly awkward and nonconforming
- * appearance.
- */
-
-/*
- * Is this a device that supports enclosure services?
- *
- * It's a pretty simple ruleset- if it is device type 0x0D (13), it's
- * an SES device. If it happens to be an old UNISYS SEN device, we can
- * handle that too.
- */
-
-#define	SAFTE_START	44
-#define	SAFTE_END	50
-#define	SAFTE_LEN	SAFTE_END-SAFTE_START
-
-static enctyp
-ses_type(void *buf, int buflen)
-{
-	unsigned char *iqd = buf;
-
-	if (buflen < 8+SEN_ID_LEN)
-		return (SES_NONE);
-
-	if ((iqd[0] & 0x1f) == T_ENCLOSURE) {
-		if (STRNCMP(&iqd[8], SEN_ID, SEN_ID_LEN) == 0) {
-			return (SES_SEN);
-		} else if ((iqd[2] & 0x7) > 2) {
-			return (SES_SES);
-		} else {
-			return (SES_SES_SCSI2);
-		}
-		return (SES_NONE);
-	}
-
-#ifdef	SES_ENABLE_PASSTHROUGH
-	if ((iqd[6] & 0x40) && (iqd[2] & 0x7) >= 2) {
-		/*
-		 * PassThrough Device.
-		 */
-		return (SES_SES_PASSTHROUGH);
-	}
-#endif
-
-	/*
-	 * The comparison is short for a reason-
-	 * some vendors were chopping it short.
-	 */
-
-	if (buflen < SAFTE_END - 2) {
-		return (SES_NONE);
-	}
-
-	if (STRNCMP((char *)&iqd[SAFTE_START], "SAF-TE", SAFTE_LEN - 2) == 0) {
-		return (SES_SAFT);
-	}
-	return (SES_NONE);
-}
-
-/*
- * SES Native Type Device Support
- */
-
-/*
- * SES Diagnostic Page Codes
- */
-
-typedef enum {
-	SesConfigPage = 0x1,
-	SesControlPage,
-#define	SesStatusPage SesControlPage
-	SesHelpTxt,
-	SesStringOut,
-#define	SesStringIn	SesStringOut
-	SesThresholdOut,
-#define	SesThresholdIn SesThresholdOut
-	SesArrayControl,
-#define	SesArrayStatus	SesArrayControl
-	SesElementDescriptor,
-	SesShortStatus
-} SesDiagPageCodes;
-
-/*
- * minimal amounts
- */
-
-/*
- * Minimum amount of data, starting from byte 0, to have
- * the config header.
- */
-#define	SES_CFGHDR_MINLEN	12
-
-/*
- * Minimum amount of data, starting from byte 0, to have
- * the config header and one enclosure header.
- */
-#define	SES_ENCHDR_MINLEN	48
-
-/*
- * Take this value, subtract it from VEnclen and you know
- * the length of the vendor unique bytes.
- */
-#define	SES_ENCHDR_VMIN		36
-
-/*
- * SES Data Structures
- */
-
-typedef struct {
-	uint32_t GenCode;	/* Generation Code */
-	uint8_t	Nsubenc;	/* Number of Subenclosures */
-} SesCfgHdr;
-
-typedef struct {
-	uint8_t	Subencid;	/* SubEnclosure Identifier */
-	uint8_t	Ntypes;		/* # of supported types */
-	uint8_t	VEnclen;	/* Enclosure Descriptor Length */
-} SesEncHdr;
-
-typedef struct {
-	uint8_t	encWWN[8];	/* XXX- Not Right Yet */
-	uint8_t	encVid[8];
-	uint8_t	encPid[16];
-	uint8_t	encRev[4];
-	uint8_t	encVen[1];
-} SesEncDesc;
-
-typedef struct {
-	uint8_t	enc_type;		/* type of element */
-	uint8_t	enc_maxelt;		/* maximum supported */
-	uint8_t	enc_subenc;		/* in SubEnc # N */
-	uint8_t	enc_tlen;		/* Type Descriptor Text Length */
-} SesThdr;
-
-typedef struct {
-	uint8_t	comstatus;
-	uint8_t	comstat[3];
-} SesComStat;
-
-struct typidx {
-	int ses_tidx;
-	int ses_oidx;
-};
-
-struct sscfg {
-	uint8_t ses_ntypes;	/* total number of types supported */
-
-	/*
-	 * We need to keep a type index as well as an
-	 * object index for each object in an enclosure.
-	 */
-	struct typidx *ses_typidx;
-
-	/*
-	 * We also need to keep track of the number of elements
-	 * per type of element. This is needed later so that we
-	 * can find precisely in the returned status data the
-	 * status for the Nth element of the Kth type.
-	 */
-	uint8_t *	ses_eltmap;
-};
-
-
-/*
- * (de)canonicalization defines
- */
-#define	sbyte(x, byte)		((((uint32_t)(x)) >> (byte * 8)) & 0xff)
-#define	sbit(x, bit)		(((uint32_t)(x)) << bit)
-#define	sset8(outp, idx, sval)	(((uint8_t *)(outp))[idx++]) = sbyte(sval, 0)
-
-#define	sset16(outp, idx, sval)	\
-	(((uint8_t *)(outp))[idx++]) = sbyte(sval, 1), \
-	(((uint8_t *)(outp))[idx++]) = sbyte(sval, 0)
-
-
-#define	sset24(outp, idx, sval)	\
-	(((uint8_t *)(outp))[idx++]) = sbyte(sval, 2), \
-	(((uint8_t *)(outp))[idx++]) = sbyte(sval, 1), \
-	(((uint8_t *)(outp))[idx++]) = sbyte(sval, 0)
-
-
-#define	sset32(outp, idx, sval)	\
-	(((uint8_t *)(outp))[idx++]) = sbyte(sval, 3), \
-	(((uint8_t *)(outp))[idx++]) = sbyte(sval, 2), \
-	(((uint8_t *)(outp))[idx++]) = sbyte(sval, 1), \
-	(((uint8_t *)(outp))[idx++]) = sbyte(sval, 0)
-
-#define	gbyte(x, byte)	((((uint32_t)(x)) & 0xff) << (byte * 8))
-#define	gbit(lv, in, idx, shft, mask)	lv = ((in[idx] >> shft) & mask)
-#define	sget8(inp, idx, lval)	lval = (((uint8_t *)(inp))[idx++])
-#define	gget8(inp, idx, lval)	lval = (((uint8_t *)(inp))[idx])
-
-#define	sget16(inp, idx, lval)	\
-	lval = gbyte((((uint8_t *)(inp))[idx]), 1) | \
-		(((uint8_t *)(inp))[idx+1]), idx += 2
-
-#define	gget16(inp, idx, lval)	\
-	lval = gbyte((((uint8_t *)(inp))[idx]), 1) | \
-		(((uint8_t *)(inp))[idx+1])
-
-#define	sget24(inp, idx, lval)	\
-	lval = gbyte((((uint8_t *)(inp))[idx]), 2) | \
-		gbyte((((uint8_t *)(inp))[idx+1]), 1) | \
-			(((uint8_t *)(inp))[idx+2]), idx += 3
-
-#define	gget24(inp, idx, lval)	\
-	lval = gbyte((((uint8_t *)(inp))[idx]), 2) | \
-		gbyte((((uint8_t *)(inp))[idx+1]), 1) | \
-			(((uint8_t *)(inp))[idx+2])
-
-#define	sget32(inp, idx, lval)	\
-	lval = gbyte((((uint8_t *)(inp))[idx]), 3) | \
-		gbyte((((uint8_t *)(inp))[idx+1]), 2) | \
-		gbyte((((uint8_t *)(inp))[idx+2]), 1) | \
-			(((uint8_t *)(inp))[idx+3]), idx += 4
-
-#define	gget32(inp, idx, lval)	\
-	lval = gbyte((((uint8_t *)(inp))[idx]), 3) | \
-		gbyte((((uint8_t *)(inp))[idx+1]), 2) | \
-		gbyte((((uint8_t *)(inp))[idx+2]), 1) | \
-			(((uint8_t *)(inp))[idx+3])
-
-#define	SCSZ	0x2000
-#define	CFLEN	(256 + SES_ENCHDR_MINLEN)
-
-/*
- * Routines specific && private to SES only
- */
-
-static int ses_getconfig(ses_softc_t *);
-static int ses_getputstat(ses_softc_t *, int, SesComStat *, int, int);
-static int ses_cfghdr(uint8_t *, int, SesCfgHdr *);
-static int ses_enchdr(uint8_t *, int, uint8_t, SesEncHdr *);
-static int ses_encdesc(uint8_t *, int, uint8_t, SesEncDesc *);
-static int ses_getthdr(uint8_t *, int,  int, SesThdr *);
-static int ses_decode(char *, int, uint8_t *, int, int, SesComStat *);
-static int ses_encode(char *, int, uint8_t *, int, int, SesComStat *);
-
-static int
-ses_softc_init(ses_softc_t *ssc, int doinit)
-{
-	if (doinit == 0) {
-		struct sscfg *cc;
-		if (ssc->ses_nobjects) {
-			SES_FREE(ssc->ses_objmap,
-			    ssc->ses_nobjects * sizeof (encobj));
-			ssc->ses_objmap = NULL;
-		}
-		if ((cc = ssc->ses_private) != NULL) {
-			if (cc->ses_eltmap && cc->ses_ntypes) {
-				SES_FREE(cc->ses_eltmap, cc->ses_ntypes);
-				cc->ses_eltmap = NULL;
-				cc->ses_ntypes = 0;
-			}
-			if (cc->ses_typidx && ssc->ses_nobjects) {
-				SES_FREE(cc->ses_typidx,
-				    ssc->ses_nobjects * sizeof (struct typidx));
-				cc->ses_typidx = NULL;
-			}
-			SES_FREE(cc, sizeof (struct sscfg));
-			ssc->ses_private = NULL;
-		}
-		ssc->ses_nobjects = 0;
-		return (0);
-	}
-	if (ssc->ses_private == NULL) {
-		ssc->ses_private = SES_MALLOC(sizeof (struct sscfg));
-	}
-	if (ssc->ses_private == NULL) {
-		return (ENOMEM);
-	}
-	ssc->ses_nobjects = 0;
-	ssc->ses_encstat = 0;
-	return (ses_getconfig(ssc));
-}
-
-static int
-ses_init_enc(ses_softc_t *ssc)
-{
-	return (0);
-}
-
-static int
-ses_get_encstat(ses_softc_t *ssc, int slpflag)
-{
-	SesComStat ComStat;
-	int status;
-
-	if ((status = ses_getputstat(ssc, -1, &ComStat, slpflag, 1)) != 0) {
-		return (status);
-	}
-	ssc->ses_encstat = ComStat.comstatus | ENCI_SVALID;
-	return (0);
-}
-
-static int
-ses_set_encstat(ses_softc_t *ssc, uint8_t encstat, int slpflag)
-{
-	SesComStat ComStat;
-	int status;
-
-	ComStat.comstatus = encstat & 0xf;
-	if ((status = ses_getputstat(ssc, -1, &ComStat, slpflag, 0)) != 0) {
-		return (status);
-	}
-	ssc->ses_encstat = encstat & 0xf;	/* note no SVALID set */
-	return (0);
-}
-
-static int
-ses_get_objstat(ses_softc_t *ssc, ses_objstat *obp, int slpflag)
-{
-	int i = (int)obp->obj_id;
-
-	if (ssc->ses_objmap[i].svalid == 0) {
-		SesComStat ComStat;
-		int err = ses_getputstat(ssc, i, &ComStat, slpflag, 1);
-		if (err)
-			return (err);
-		ssc->ses_objmap[i].encstat[0] = ComStat.comstatus;
-		ssc->ses_objmap[i].encstat[1] = ComStat.comstat[0];
-		ssc->ses_objmap[i].encstat[2] = ComStat.comstat[1];
-		ssc->ses_objmap[i].encstat[3] = ComStat.comstat[2];
-		ssc->ses_objmap[i].svalid = 1;
-	}
-	obp->cstat[0] = ssc->ses_objmap[i].encstat[0];
-	obp->cstat[1] = ssc->ses_objmap[i].encstat[1];
-	obp->cstat[2] = ssc->ses_objmap[i].encstat[2];
-	obp->cstat[3] = ssc->ses_objmap[i].encstat[3];
-	return (0);
-}
-
-static int
-ses_set_objstat(ses_softc_t *ssc, ses_objstat *obp, int slpflag)
-{
-	SesComStat ComStat;
-	int err;
-	/*
-	 * If this is clear, we don't do diddly.
-	 */
-	if ((obp->cstat[0] & SESCTL_CSEL) == 0) {
-		return (0);
-	}
-	ComStat.comstatus = obp->cstat[0];
-	ComStat.comstat[0] = obp->cstat[1];
-	ComStat.comstat[1] = obp->cstat[2];
-	ComStat.comstat[2] = obp->cstat[3];
-	err = ses_getputstat(ssc, (int)obp->obj_id, &ComStat, slpflag, 0);
-	ssc->ses_objmap[(int)obp->obj_id].svalid = 0;
-	return (err);
-}
-
-static int
-ses_getconfig(ses_softc_t *ssc)
-{
-	struct sscfg *cc;
-	SesCfgHdr cf;
-	SesEncHdr hd;
-	SesEncDesc *cdp;
-	SesThdr thdr;
-	int err, amt, i, nobj, ntype, maxima;
-	char storage[CFLEN], *sdata;
-	static char cdb[6] = {
-	    RECEIVE_DIAGNOSTIC, 0x1, SesConfigPage, SCSZ >> 8, SCSZ & 0xff, 0
-	};
-
-	cc = ssc->ses_private;
-	if (cc == NULL) {
-		return (ENXIO);
-	}
-
-	sdata = SES_MALLOC(SCSZ);
-	if (sdata == NULL)
-		return (ENOMEM);
-
-	amt = SCSZ;
-	err = ses_runcmd(ssc, cdb, 6, sdata, &amt);
-	if (err) {
-		SES_FREE(sdata, SCSZ);
-		return (err);
-	}
-	amt = SCSZ - amt;
-
-	if (ses_cfghdr((uint8_t *) sdata, amt, &cf)) {
-		SES_LOG(ssc, "Unable to parse SES Config Header\n");
-		SES_FREE(sdata, SCSZ);
-		return (EIO);
-	}
-	if (amt < SES_ENCHDR_MINLEN) {
-		SES_LOG(ssc, "runt enclosure length (%d)\n", amt);
-		SES_FREE(sdata, SCSZ);
-		return (EIO);
-	}
-
-	SES_VLOG(ssc, "GenCode %x %d Subenclosures\n", cf.GenCode, cf.Nsubenc);
-
-	/*
-	 * Now waltz through all the subenclosures toting up the
-	 * number of types available in each. For this, we only
-	 * really need the enclosure header. However, we get the
-	 * enclosure descriptor for debug purposes, as well
-	 * as self-consistency checking purposes.
-	 */
-
-	maxima = cf.Nsubenc + 1;
-	cdp = (SesEncDesc *) storage;
-	for (ntype = i = 0; i < maxima; i++) {
-		MEMZERO((caddr_t)cdp, sizeof (*cdp));
-		if (ses_enchdr((uint8_t *) sdata, amt, i, &hd)) {
-			SES_LOG(ssc, "Cannot Extract Enclosure Header %d\n", i);
-			SES_FREE(sdata, SCSZ);
-			return (EIO);
-		}
-		SES_VLOG(ssc, " SubEnclosure ID %d, %d Types With this ID, En"
-		    "closure Length %d\n", hd.Subencid, hd.Ntypes, hd.VEnclen);
-
-		if (ses_encdesc((uint8_t *)sdata, amt, i, cdp)) {
-			SES_LOG(ssc, "Can't get Enclosure Descriptor %d\n", i);
-			SES_FREE(sdata, SCSZ);
-			return (EIO);
-		}
-		SES_VLOG(ssc, " WWN: %02x%02x%02x%02x%02x%02x%02x%02x\n",
-		    cdp->encWWN[0], cdp->encWWN[1], cdp->encWWN[2],
-		    cdp->encWWN[3], cdp->encWWN[4], cdp->encWWN[5],
-		    cdp->encWWN[6], cdp->encWWN[7]);
-		ntype += hd.Ntypes;
-	}
-
-	/*
-	 * Now waltz through all the types that are available, getting
-	 * the type header so we can start adding up the number of
-	 * objects available.
-	 */
-	for (nobj = i = 0; i < ntype; i++) {
-		if (ses_getthdr((uint8_t *)sdata, amt, i, &thdr)) {
-			SES_LOG(ssc, "Can't get Enclosure Type Header %d\n", i);
-			SES_FREE(sdata, SCSZ);
-			return (EIO);
-		}
-		SES_LOG(ssc, " Type Desc[%d]: Type 0x%x, MaxElt %d, In Subenc "
-		    "%d, Text Length %d\n", i, thdr.enc_type, thdr.enc_maxelt,
-		    thdr.enc_subenc, thdr.enc_tlen);
-		nobj += thdr.enc_maxelt;
-	}
-
-
-	/*
-	 * Now allocate the object array and type map.
-	 */
-
-	ssc->ses_objmap = SES_MALLOC(nobj * sizeof (encobj));
-	cc->ses_typidx = SES_MALLOC(nobj * sizeof (struct typidx));
-	cc->ses_eltmap = SES_MALLOC(ntype);
-
-	if (ssc->ses_objmap == NULL || cc->ses_typidx == NULL ||
-	    cc->ses_eltmap == NULL) {
-		if (ssc->ses_objmap) {
-			SES_FREE(ssc->ses_objmap, (nobj * sizeof (encobj)));
-			ssc->ses_objmap = NULL;
-		}
-		if (cc->ses_typidx) {
-			SES_FREE(cc->ses_typidx,
-			    (nobj * sizeof (struct typidx)));
-			cc->ses_typidx = NULL;
-		}
-		if (cc->ses_eltmap) {
-			SES_FREE(cc->ses_eltmap, ntype);
-			cc->ses_eltmap = NULL;
-		}
-		SES_FREE(sdata, SCSZ);
-		return (ENOMEM);
-	}
-	MEMZERO(ssc->ses_objmap, nobj * sizeof (encobj));
-	MEMZERO(cc->ses_typidx, nobj * sizeof (struct typidx));
-	MEMZERO(cc->ses_eltmap, ntype);
-	cc->ses_ntypes = (uint8_t) ntype;
-	ssc->ses_nobjects = nobj;
-
-	/*
-	 * Now waltz through the # of types again to fill in the types
-	 * (and subenclosure ids) of the allocated objects.
-	 */
-	nobj = 0;
-	for (i = 0; i < ntype; i++) {
-		int j;
-		if (ses_getthdr((uint8_t *)sdata, amt, i, &thdr)) {
-			continue;
-		}
-		cc->ses_eltmap[i] = thdr.enc_maxelt;
-		for (j = 0; j < thdr.enc_maxelt; j++) {
-			cc->ses_typidx[nobj].ses_tidx = i;
-			cc->ses_typidx[nobj].ses_oidx = j;
-			ssc->ses_objmap[nobj].subenclosure = thdr.enc_subenc;
-			ssc->ses_objmap[nobj++].enctype = thdr.enc_type;
-		}
-	}
-	SES_FREE(sdata, SCSZ);
-	return (0);
-}
-
-static int
-ses_getputstat(ses_softc_t *ssc, int objid, SesComStat *sp, int slp, int in)
-{
-	struct sscfg *cc;
-	int err, amt, bufsiz, tidx, oidx;
-	char cdb[6], *sdata;
-
-	cc = ssc->ses_private;
-	if (cc == NULL) {
-		return (ENXIO);
-	}
-
-	/*
-	 * If we're just getting overall enclosure status,
-	 * we only need 2 bytes of data storage.
-	 *
-	 * If we're getting anything else, we know how much
-	 * storage we need by noting that starting at offset
-	 * 8 in returned data, all object status bytes are 4
-	 * bytes long, and are stored in chunks of types(M)
-	 * and nth+1 instances of type M.
-	 */
-	if (objid == -1) {
-		bufsiz = 2;
-	} else {
-		bufsiz = (ssc->ses_nobjects * 4) + (cc->ses_ntypes * 4) + 8;
-	}
-	sdata = SES_MALLOC(bufsiz);
-	if (sdata == NULL)
-		return (ENOMEM);
-
-	cdb[0] = RECEIVE_DIAGNOSTIC;
-	cdb[1] = 1;
-	cdb[2] = SesStatusPage;
-	cdb[3] = bufsiz >> 8;
-	cdb[4] = bufsiz & 0xff;
-	cdb[5] = 0;
-	amt = bufsiz;
-	err = ses_runcmd(ssc, cdb, 6, sdata, &amt);
-	if (err) {
-		SES_FREE(sdata, bufsiz);
-		return (err);
-	}
-	amt = bufsiz - amt;
-
-	if (objid == -1) {
-		tidx = -1;
-		oidx = -1;
-	} else {
-		tidx = cc->ses_typidx[objid].ses_tidx;
-		oidx = cc->ses_typidx[objid].ses_oidx;
-	}
-	if (in) {
-		if (ses_decode(sdata, amt, cc->ses_eltmap, tidx, oidx, sp)) {
-			err = ENODEV;
-		}
-	} else {
-		if (ses_encode(sdata, amt, cc->ses_eltmap, tidx, oidx, sp)) {
-			err = ENODEV;
-		} else {
-			cdb[0] = SEND_DIAGNOSTIC;
-			cdb[1] = 0x10;
-			cdb[2] = 0;
-			cdb[3] = bufsiz >> 8;
-			cdb[4] = bufsiz & 0xff;
-			cdb[5] = 0;
-			amt = -bufsiz;
-			err = ses_runcmd(ssc, cdb, 6, sdata, &amt);   
-		}
-	}
-	SES_FREE(sdata, bufsiz);
-	return (0);
-}
-
-
-/*
- * Routines to parse returned SES data structures.
- * Architecture and compiler independent.
- */
-
-static int
-ses_cfghdr(uint8_t *buffer, int buflen, SesCfgHdr *cfp)
-{
-	if (buflen < SES_CFGHDR_MINLEN) {
-		return (-1);
-	}
-	gget8(buffer, 1, cfp->Nsubenc);
-	gget32(buffer, 4, cfp->GenCode);
-	return (0);
-}
-
-static int
-ses_enchdr(uint8_t *buffer, int amt, uint8_t SubEncId, SesEncHdr *chp)
-{
-	int s, off = 8;
-	for (s = 0; s < SubEncId; s++) {
-		if (off + 3 > amt)
-			return (-1);
-		off += buffer[off+3] + 4;
-	}
-	if (off + 3 > amt) {
-		return (-1);
-	}
-	gget8(buffer, off+1, chp->Subencid);
-	gget8(buffer, off+2, chp->Ntypes);
-	gget8(buffer, off+3, chp->VEnclen);
-	return (0);
-}
-
-static int
-ses_encdesc(uint8_t *buffer, int amt, uint8_t SubEncId, SesEncDesc *cdp)
-{
-	int s, e, enclen, off = 8;
-	for (s = 0; s < SubEncId; s++) {
-		if (off + 3 > amt)
-			return (-1);
-		off += buffer[off+3] + 4;
-	}
-	if (off + 3 > amt) {
-		return (-1);
-	}
-	gget8(buffer, off+3, enclen);
-	off += 4;
-	if (off  >= amt)
-		return (-1);
-
-	e = off + enclen;
-	if (e > amt) {
-		e = amt;
-	}
-	MEMCPY(cdp, &buffer[off], e - off);
-	return (0);
-}
-
-static int
-ses_getthdr(uint8_t *buffer, int amt, int nth, SesThdr *thp)
-{
-	int s, off = 8;
-
-	if (amt < SES_CFGHDR_MINLEN) {
-		return (-1);
-	}
-	for (s = 0; s < buffer[1]; s++) {
-		if (off + 3 > amt)
-			return (-1);
-		off += buffer[off+3] + 4;
-	}
-	if (off + 3 > amt) {
-		return (-1);
-	}
-	off += buffer[off+3] + 4 + (nth * 4);
-	if (amt < (off + 4))
-		return (-1);
-
-	gget8(buffer, off++, thp->enc_type);
-	gget8(buffer, off++, thp->enc_maxelt);
-	gget8(buffer, off++, thp->enc_subenc);
-	gget8(buffer, off, thp->enc_tlen);
-	return (0);
-}
-
-/*
- * This function needs a little explanation.
- *
- * The arguments are:
- *
- *
- *	char *b, int amt
- *
- *		These describes the raw input SES status data and length.
- *
- *	uint8_t *ep
- *
- *		This is a map of the number of types for each element type
- *		in the enclosure.
- *
- *	int elt
- *
- *		This is the element type being sought. If elt is -1,
- *		then overall enclosure status is being sought.
- *
- *	int elm
- *
- *		This is the ordinal Mth element of type elt being sought.
- *
- *	SesComStat *sp
- *
- *		This is the output area to store the status for
- *		the Mth element of type Elt.
- */
-
-static int
-ses_decode(char *b, int amt, uint8_t *ep, int elt, int elm, SesComStat *sp)
-{
-	int idx, i;
-
-	/*
-	 * If it's overall enclosure status being sought, get that.
-	 * We need at least 2 bytes of status data to get that.
-	 */
-	if (elt == -1) {
-		if (amt < 2)
-			return (-1);
-		gget8(b, 1, sp->comstatus);
-		sp->comstat[0] = 0;
-		sp->comstat[1] = 0;
-		sp->comstat[2] = 0;
-		return (0);
-	}
-
-	/*
-	 * Check to make sure that the Mth element is legal for type Elt.
-	 */
-
-	if (elm >= ep[elt])
-		return (-1);
-
-	/*
-	 * Starting at offset 8, start skipping over the storage
-	 * for the element types we're not interested in.
-	 */
-	for (idx = 8, i = 0; i < elt; i++) {
-		idx += ((ep[i] + 1) * 4);
-	}
-
-	/*
-	 * Skip over Overall status for this element type.
-	 */
-	idx += 4;
-
-	/*
-	 * And skip to the index for the Mth element that we're going for.
-	 */
-	idx += (4 * elm);
-
-	/*
-	 * Make sure we haven't overflowed the buffer.
-	 */
-	if (idx+4 > amt)
-		return (-1);
-
-	/*
-	 * Retrieve the status.
-	 */
-	gget8(b, idx++, sp->comstatus);
-	gget8(b, idx++, sp->comstat[0]);
-	gget8(b, idx++, sp->comstat[1]);
-	gget8(b, idx++, sp->comstat[2]);
-#if	0
-	PRINTF("Get Elt 0x%x Elm 0x%x (idx %d)\n", elt, elm, idx-4);
-#endif
-	return (0);
-}
-
-/*
- * This is the mirror function to ses_decode, but we set the 'select'
- * bit for the object which we're interested in. All other objects,
- * after a status fetch, should have that bit off. Hmm. It'd be easy
- * enough to ensure this, so we will.
- */
-
-static int
-ses_encode(char *b, int amt, uint8_t *ep, int elt, int elm, SesComStat *sp)
-{
-	int idx, i;
-
-	/*
-	 * If it's overall enclosure status being sought, get that.
-	 * We need at least 2 bytes of status data to get that.
-	 */
-	if (elt == -1) {
-		if (amt < 2)
-			return (-1);
-		i = 0;
-		sset8(b, i, 0);
-		sset8(b, i, sp->comstatus & 0xf);
-#if	0
-		PRINTF("set EncStat %x\n", sp->comstatus);
-#endif
-		return (0);
-	}
-
-	/*
-	 * Check to make sure that the Mth element is legal for type Elt.
-	 */
-
-	if (elm >= ep[elt])
-		return (-1);
-
-	/*
-	 * Starting at offset 8, start skipping over the storage
-	 * for the element types we're not interested in.
-	 */
-	for (idx = 8, i = 0; i < elt; i++) {
-		idx += ((ep[i] + 1) * 4);
-	}
-
-	/*
-	 * Skip over Overall status for this element type.
-	 */
-	idx += 4;
-
-	/*
-	 * And skip to the index for the Mth element that we're going for.
-	 */
-	idx += (4 * elm);
-
-	/*
-	 * Make sure we haven't overflowed the buffer.
-	 */
-	if (idx+4 > amt)
-		return (-1);
-
-	/*
-	 * Set the status.
-	 */
-	sset8(b, idx, sp->comstatus);
-	sset8(b, idx, sp->comstat[0]);
-	sset8(b, idx, sp->comstat[1]);
-	sset8(b, idx, sp->comstat[2]);
-	idx -= 4;
-
-#if	0
-	PRINTF("Set Elt 0x%x Elm 0x%x (idx %d) with %x %x %x %x\n",
-	    elt, elm, idx, sp->comstatus, sp->comstat[0],
-	    sp->comstat[1], sp->comstat[2]);
-#endif
-
-	/*
-	 * Now make sure all other 'Select' bits are off.
-	 */
-	for (i = 8; i < amt; i += 4) {
-		if (i != idx)
-			b[i] &= ~0x80;
-	}
-	/*
-	 * And make sure the INVOP bit is clear.
-	 */
-	b[2] &= ~0x10;
-
-	return (0);
-}
-
-/*
- * SAF-TE Type Device Emulation
- */
-
-static int safte_getconfig(ses_softc_t *);
-static int safte_rdstat(ses_softc_t *, int);
-static int set_objstat_sel(ses_softc_t *, ses_objstat *, int);
-static int wrbuf16(ses_softc_t *, uint8_t, uint8_t, uint8_t, uint8_t, int);
-static void wrslot_stat(ses_softc_t *, int);
-static int perf_slotop(ses_softc_t *, uint8_t, uint8_t, int);
-
-#define	ALL_ENC_STAT (SES_ENCSTAT_CRITICAL | SES_ENCSTAT_UNRECOV | \
-	SES_ENCSTAT_NONCRITICAL | SES_ENCSTAT_INFO)
-/*
- * SAF-TE specific defines- Mandatory ones only...
- */
-
-/*
- * READ BUFFER ('get' commands) IDs- placed in offset 2 of cdb
- */
-#define	SAFTE_RD_RDCFG	0x00	/* read enclosure configuration */
-#define	SAFTE_RD_RDESTS	0x01	/* read enclosure status */
-#define	SAFTE_RD_RDDSTS	0x04	/* read drive slot status */
-
-/*
- * WRITE BUFFER ('set' commands) IDs- placed in offset 0 of databuf
- */
-#define	SAFTE_WT_DSTAT	0x10	/* write device slot status */
-#define	SAFTE_WT_SLTOP	0x12	/* perform slot operation */
-#define	SAFTE_WT_FANSPD	0x13	/* set fan speed */
-#define	SAFTE_WT_ACTPWS	0x14	/* turn on/off power supply */
-#define	SAFTE_WT_GLOBAL	0x15	/* send global command */
-
-
-#define	SAFT_SCRATCH	64
-#define	NPSEUDO_THERM	16
-#define	NPSEUDO_ALARM	1
-struct scfg {
-	/*
-	 * Cached Configuration
-	 */
-	uint8_t	Nfans;		/* Number of Fans */
-	uint8_t	Npwr;		/* Number of Power Supplies */
-	uint8_t	Nslots;		/* Number of Device Slots */
-	uint8_t	DoorLock;	/* Door Lock Installed */
-	uint8_t	Ntherm;		/* Number of Temperature Sensors */
-	uint8_t	Nspkrs;		/* Number of Speakers */
-	uint8_t Nalarm;		/* Number of Alarms (at least one) */
-	/*
-	 * Cached Flag Bytes for Global Status
-	 */
-	uint8_t	flag1;
-	uint8_t	flag2;
-	/*
-	 * What object index ID is where various slots start.
-	 */
-	uint8_t	pwroff;
-	uint8_t	slotoff;
-#define	SAFT_ALARM_OFFSET(cc)	(cc)->slotoff - 1
-};
-
-#define	SAFT_FLG1_ALARM		0x1
-#define	SAFT_FLG1_GLOBFAIL	0x2
-#define	SAFT_FLG1_GLOBWARN	0x4
-#define	SAFT_FLG1_ENCPWROFF	0x8
-#define	SAFT_FLG1_ENCFANFAIL	0x10
-#define	SAFT_FLG1_ENCPWRFAIL	0x20
-#define	SAFT_FLG1_ENCDRVFAIL	0x40
-#define	SAFT_FLG1_ENCDRVWARN	0x80
-
-#define	SAFT_FLG2_LOCKDOOR	0x4
-#define	SAFT_PRIVATE		sizeof (struct scfg)
-
-static char *safte_2little = "Too Little Data Returned (%d) at line %d\n";
-#define	SAFT_BAIL(r, x, k, l)	\
-	if ((r) >= (x)) { \
-		SES_LOG(ssc, safte_2little, x, __LINE__);\
-		SES_FREE((k), (l)); \
-		return (EIO); \
-	}
-
-
-static int
-safte_softc_init(ses_softc_t *ssc, int doinit)
-{
-	int err, i, r;
-	struct scfg *cc;
-
-	if (doinit == 0) {
-		if (ssc->ses_nobjects) {
-			if (ssc->ses_objmap) {
-				SES_FREE(ssc->ses_objmap,
-				    ssc->ses_nobjects * sizeof (encobj));
-				ssc->ses_objmap = NULL;
-			}
-			ssc->ses_nobjects = 0;
-		}
-		if (ssc->ses_private) {
-			SES_FREE(ssc->ses_private, SAFT_PRIVATE);
-			ssc->ses_private = NULL;
-		}
-		return (0);
-	}
-
-	if (ssc->ses_private == NULL) {
-		ssc->ses_private = SES_MALLOC(SAFT_PRIVATE);
-		if (ssc->ses_private == NULL) {
-			return (ENOMEM);
-		}
-		MEMZERO(ssc->ses_private, SAFT_PRIVATE);
-	}
-
-	ssc->ses_nobjects = 0;
-	ssc->ses_encstat = 0;
-
-	if ((err = safte_getconfig(ssc)) != 0) {
-		return (err);
-	}
-
-	/*
-	 * The number of objects here, as well as that reported by the
-	 * READ_BUFFER/GET_CONFIG call, are the over-temperature flags (15)
-	 * that get reported during READ_BUFFER/READ_ENC_STATUS.
-	 */
-	cc = ssc->ses_private;
-	ssc->ses_nobjects = cc->Nfans + cc->Npwr + cc->Nslots + cc->DoorLock +
-	    cc->Ntherm + cc->Nspkrs + NPSEUDO_THERM + NPSEUDO_ALARM;
-	ssc->ses_objmap = (encobj *)
-	    SES_MALLOC(ssc->ses_nobjects * sizeof (encobj));
-	if (ssc->ses_objmap == NULL) {
-		return (ENOMEM);
-	}
-	MEMZERO(ssc->ses_objmap, ssc->ses_nobjects * sizeof (encobj));
-
-	r = 0;
-	/*
-	 * Note that this is all arranged for the convenience
-	 * in later fetches of status.
-	 */
-	for (i = 0; i < cc->Nfans; i++)
-		ssc->ses_objmap[r++].enctype = SESTYP_FAN;
-	cc->pwroff = (uint8_t) r;
-	for (i = 0; i < cc->Npwr; i++)
-		ssc->ses_objmap[r++].enctype = SESTYP_POWER;
-	for (i = 0; i < cc->DoorLock; i++)
-		ssc->ses_objmap[r++].enctype = SESTYP_DOORLOCK;
-	for (i = 0; i < cc->Nspkrs; i++)
-		ssc->ses_objmap[r++].enctype = SESTYP_ALARM;
-	for (i = 0; i < cc->Ntherm; i++)
-		ssc->ses_objmap[r++].enctype = SESTYP_THERM;
-	for (i = 0; i < NPSEUDO_THERM; i++)
-		ssc->ses_objmap[r++].enctype = SESTYP_THERM;
-	ssc->ses_objmap[r++].enctype = SESTYP_ALARM;
-	cc->slotoff = (uint8_t) r;
-	for (i = 0; i < cc->Nslots; i++)
-		ssc->ses_objmap[r++].enctype = SESTYP_DEVICE;
-	return (0);
-}
-
-static int
-safte_init_enc(ses_softc_t *ssc)
-{
-	int err;
-	static char cdb0[6] = { SEND_DIAGNOSTIC };
-
-	err = ses_runcmd(ssc, cdb0, 6, NULL, 0);
-	if (err) {
-		return (err);
-	}
-	DELAY(5000);
-	err = wrbuf16(ssc, SAFTE_WT_GLOBAL, 0, 0, 0, 1);
-	return (err);
-}
-
-static int
-safte_get_encstat(ses_softc_t *ssc, int slpflg)
-{
-	return (safte_rdstat(ssc, slpflg));
-}
-
-static int
-safte_set_encstat(ses_softc_t *ssc, uint8_t encstat, int slpflg)
-{
-	struct scfg *cc = ssc->ses_private;
-	if (cc == NULL)
-		return (0);
-	/*
-	 * Since SAF-TE devices aren't necessarily sticky in terms
-	 * of state, make our soft copy of enclosure status 'sticky'-
-	 * that is, things set in enclosure status stay set (as implied
-	 * by conditions set in reading object status) until cleared.
-	 */
-	ssc->ses_encstat &= ~ALL_ENC_STAT;
-	ssc->ses_encstat |= (encstat & ALL_ENC_STAT);
-	ssc->ses_encstat |= ENCI_SVALID;
-	cc->flag1 &= ~(SAFT_FLG1_ALARM|SAFT_FLG1_GLOBFAIL|SAFT_FLG1_GLOBWARN);
-	if ((encstat & (SES_ENCSTAT_CRITICAL|SES_ENCSTAT_UNRECOV)) != 0) {
-		cc->flag1 |= SAFT_FLG1_ALARM|SAFT_FLG1_GLOBFAIL;
-	} else if ((encstat & SES_ENCSTAT_NONCRITICAL) != 0) {
-		cc->flag1 |= SAFT_FLG1_GLOBWARN;
-	}
-	return (wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, cc->flag2, 0, slpflg));
-}
-
-static int
-safte_get_objstat(ses_softc_t *ssc, ses_objstat *obp, int slpflg)
-{
-	int i = (int)obp->obj_id;
-
-	if ((ssc->ses_encstat & ENCI_SVALID) == 0 ||
-	    (ssc->ses_objmap[i].svalid) == 0) {
-		int err = safte_rdstat(ssc, slpflg);
-		if (err)
-			return (err);
-	}
-	obp->cstat[0] = ssc->ses_objmap[i].encstat[0];
-	obp->cstat[1] = ssc->ses_objmap[i].encstat[1];
-	obp->cstat[2] = ssc->ses_objmap[i].encstat[2];
-	obp->cstat[3] = ssc->ses_objmap[i].encstat[3];
-	return (0);
-}
-
-
-static int
-safte_set_objstat(ses_softc_t *ssc, ses_objstat *obp, int slp)
-{
-	int idx, err;
-	encobj *ep;
-	struct scfg *cc;
-
-
-	SES_DLOG(ssc, "safte_set_objstat(%d): %x %x %x %x\n",
-	    (int)obp->obj_id, obp->cstat[0], obp->cstat[1], obp->cstat[2],
-	    obp->cstat[3]);
-
-	/*
-	 * If this is clear, we don't do diddly.
-	 */
-	if ((obp->cstat[0] & SESCTL_CSEL) == 0) {
-		return (0);
-	}
-
-	err = 0;
-	/*
-	 * Check to see if the common bits are set and do them first.
-	 */
-	if (obp->cstat[0] & ~SESCTL_CSEL) {
-		err = set_objstat_sel(ssc, obp, slp);
-		if (err)
-			return (err);
-	}
-
-	cc = ssc->ses_private;
-	if (cc == NULL)
-		return (0);
-
-	idx = (int)obp->obj_id;
-	ep = &ssc->ses_objmap[idx];
-
-	switch (ep->enctype) {
-	case SESTYP_DEVICE:
-	{
-		uint8_t slotop = 0;
-		/*
-		 * XXX: I should probably cache the previous state
-		 * XXX: of SESCTL_DEVOFF so that when it goes from
-		 * XXX: true to false I can then set PREPARE FOR OPERATION
-		 * XXX: flag in PERFORM SLOT OPERATION write buffer command.
-		 */
-		if (obp->cstat[2] & (SESCTL_RQSINS|SESCTL_RQSRMV)) {
-			slotop |= 0x2;
-		}
-		if (obp->cstat[2] & SESCTL_RQSID) {
-			slotop |= 0x4;
-		}
-		err = perf_slotop(ssc, (uint8_t) idx - (uint8_t) cc->slotoff,
-		    slotop, slp);
-		if (err)
-			return (err);
-		if (obp->cstat[3] & SESCTL_RQSFLT) {
-			ep->priv |= 0x2;
-		} else {
-			ep->priv &= ~0x2;
-		}
-		if (ep->priv & 0xc6) {
-			ep->priv &= ~0x1;
-		} else {
-			ep->priv |= 0x1;	/* no errors */
-		}
-		wrslot_stat(ssc, slp);
-		break;
-	}
-	case SESTYP_POWER:
-		if (obp->cstat[3] & SESCTL_RQSTFAIL) {
-			cc->flag1 |= SAFT_FLG1_ENCPWRFAIL;
-		} else {
-			cc->flag1 &= ~SAFT_FLG1_ENCPWRFAIL;
-		}
-		err = wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
-		    cc->flag2, 0, slp);
-		if (err)
-			return (err);
-		if (obp->cstat[3] & SESCTL_RQSTON) {
-			(void) wrbuf16(ssc, SAFTE_WT_ACTPWS,
-				idx - cc->pwroff, 0, 0, slp);
-		} else {
-			(void) wrbuf16(ssc, SAFTE_WT_ACTPWS,
-				idx - cc->pwroff, 0, 1, slp);
-		}
-		break;
-	case SESTYP_FAN:
-		if (obp->cstat[3] & SESCTL_RQSTFAIL) {
-			cc->flag1 |= SAFT_FLG1_ENCFANFAIL;
-		} else {
-			cc->flag1 &= ~SAFT_FLG1_ENCFANFAIL;
-		}
-		err = wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
-		    cc->flag2, 0, slp);
-		if (err)
-			return (err);
-		if (obp->cstat[3] & SESCTL_RQSTON) {
-			uint8_t fsp;
-			if ((obp->cstat[3] & 0x7) == 7) {
-				fsp = 4;
-			} else if ((obp->cstat[3] & 0x7) == 6) {
-				fsp = 3;
-			} else if ((obp->cstat[3] & 0x7) == 4) {
-				fsp = 2;
-			} else {
-				fsp = 1;
-			}
-			(void) wrbuf16(ssc, SAFTE_WT_FANSPD, idx, fsp, 0, slp);
-		} else {
-			(void) wrbuf16(ssc, SAFTE_WT_FANSPD, idx, 0, 0, slp);
-		}
-		break;
-	case SESTYP_DOORLOCK:
-		if (obp->cstat[3] & 0x1) {
-			cc->flag2 &= ~SAFT_FLG2_LOCKDOOR;
-		} else {
-			cc->flag2 |= SAFT_FLG2_LOCKDOOR;
-		}
-		(void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
-		    cc->flag2, 0, slp);
-		break;
-	case SESTYP_ALARM:
-		/*
-		 * On all nonzero but the 'muted' bit, we turn on the alarm,
-		 */
-		obp->cstat[3] &= ~0xa;
-		if (obp->cstat[3] & 0x40) {
-			cc->flag2 &= ~SAFT_FLG1_ALARM;
-		} else if (obp->cstat[3] != 0) {
-			cc->flag2 |= SAFT_FLG1_ALARM;
-		} else {
-			cc->flag2 &= ~SAFT_FLG1_ALARM;
-		}
-		ep->priv = obp->cstat[3];
-		(void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
-			cc->flag2, 0, slp);
-		break;
-	default:
-		break;
-	}
-	ep->svalid = 0;
-	return (0);
-}
-
-static int
-safte_getconfig(ses_softc_t *ssc)
-{
-	struct scfg *cfg;
-	int err, amt;
-	char *sdata;
-	static char cdb[10] =
-	    { READ_BUFFER, 1, SAFTE_RD_RDCFG, 0, 0, 0, 0, 0, SAFT_SCRATCH, 0 };
-
-	cfg = ssc->ses_private;
-	if (cfg == NULL)
-		return (ENXIO);
-
-	sdata = SES_MALLOC(SAFT_SCRATCH);
-	if (sdata == NULL)
-		return (ENOMEM);
-
-	amt = SAFT_SCRATCH;
-	err = ses_runcmd(ssc, cdb, 10, sdata, &amt);
-	if (err) {
-		SES_FREE(sdata, SAFT_SCRATCH);
-		return (err);
-	}
-	amt = SAFT_SCRATCH - amt;
-	if (amt < 6) {
-		SES_LOG(ssc, "too little data (%d) for configuration\n", amt);
-		SES_FREE(sdata, SAFT_SCRATCH);
-		return (EIO);
-	}
-	SES_VLOG(ssc, "Nfans %d Npwr %d Nslots %d Lck %d Ntherm %d Nspkrs %d\n",
-	    sdata[0], sdata[1], sdata[2], sdata[3], sdata[4], sdata[5]);
-	cfg->Nfans = sdata[0];
-	cfg->Npwr = sdata[1];
-	cfg->Nslots = sdata[2];
-	cfg->DoorLock = sdata[3];
-	cfg->Ntherm = sdata[4];
-	cfg->Nspkrs = sdata[5];
-	cfg->Nalarm = NPSEUDO_ALARM;
-	SES_FREE(sdata, SAFT_SCRATCH);
-	return (0);
-}
-
-static int
-safte_rdstat(ses_softc_t *ssc, int slpflg)
-{
-	int err, oid, r, i, hiwater, nitems, amt;
-	uint16_t tempflags;
-	size_t buflen;
-	uint8_t status, oencstat;
-	char *sdata, cdb[10];
-	struct scfg *cc = ssc->ses_private;
-
-
-	/*
-	 * The number of objects overstates things a bit,
-	 * both for the bogus 'thermometer' entries and
-	 * the drive status (which isn't read at the same
-	 * time as the enclosure status), but that's okay.
-	 */
-	buflen = 4 * cc->Nslots;
-	if (ssc->ses_nobjects > buflen)
-		buflen = ssc->ses_nobjects;
-	sdata = SES_MALLOC(buflen);
-	if (sdata == NULL)
-		return (ENOMEM);
-
-	cdb[0] = READ_BUFFER;
-	cdb[1] = 1;
-	cdb[2] = SAFTE_RD_RDESTS;
-	cdb[3] = 0;
-	cdb[4] = 0;
-	cdb[5] = 0;
-	cdb[6] = 0;
-	cdb[7] = (buflen >> 8) & 0xff;
-	cdb[8] = buflen & 0xff;
-	cdb[9] = 0;
-	amt = buflen;
-	err = ses_runcmd(ssc, cdb, 10, sdata, &amt);
-	if (err) {
-		SES_FREE(sdata, buflen);
-		return (err);
-	}
-	hiwater = buflen - amt;
-
-
-	/*
-	 * invalidate all status bits.
-	 */
-	for (i = 0; i < ssc->ses_nobjects; i++)
-		ssc->ses_objmap[i].svalid = 0;
-	oencstat = ssc->ses_encstat & ALL_ENC_STAT;
-	ssc->ses_encstat = 0;
-
-
-	/*
-	 * Now parse returned buffer.
-	 * If we didn't get enough data back,
-	 * that's considered a fatal error.
-	 */
-	oid = r = 0;
-
-	for (nitems = i = 0; i < cc->Nfans; i++) {
-		SAFT_BAIL(r, hiwater, sdata, buflen);
-		/*
-		 * 0 = Fan Operational
-		 * 1 = Fan is malfunctioning
-		 * 2 = Fan is not present
-		 * 0x80 = Unknown or Not Reportable Status
-		 */
-		ssc->ses_objmap[oid].encstat[1] = 0;	/* resvd */
-		ssc->ses_objmap[oid].encstat[2] = 0;	/* resvd */
-		switch ((int)(uint8_t)sdata[r]) {
-		case 0:
-			nitems++;
-			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
-			/*
-			 * We could get fancier and cache
-			 * fan speeds that we have set, but
-			 * that isn't done now.
-			 */
-			ssc->ses_objmap[oid].encstat[3] = 7;
-			break;
-
-		case 1:
-			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_CRIT;
-			/*
-			 * FAIL and FAN STOPPED synthesized
-			 */
-			ssc->ses_objmap[oid].encstat[3] = 0x40;
-			/*
-			 * Enclosure marked with CRITICAL error
-			 * if only one fan or no thermometers,
-			 * else the NONCRITICAL error is set.
-			 */
-			if (cc->Nfans == 1 || cc->Ntherm == 0)
-				ssc->ses_encstat |= SES_ENCSTAT_CRITICAL;
-			else
-				ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL;
-			break;
-		case 2:
-			ssc->ses_objmap[oid].encstat[0] =
-			    SES_OBJSTAT_NOTINSTALLED;
-			ssc->ses_objmap[oid].encstat[3] = 0;
-			/*
-			 * Enclosure marked with CRITICAL error
-			 * if only one fan or no thermometers,
-			 * else the NONCRITICAL error is set.
-			 */
-			if (cc->Nfans == 1)
-				ssc->ses_encstat |= SES_ENCSTAT_CRITICAL;
-			else
-				ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL;
-			break;
-		case 0x80:
-			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNKNOWN;
-			ssc->ses_objmap[oid].encstat[3] = 0;
-			ssc->ses_encstat |= SES_ENCSTAT_INFO;
-			break;
-		default:
-			ssc->ses_objmap[oid].encstat[0] =
-			    SES_OBJSTAT_UNSUPPORTED;
-			SES_LOG(ssc, "Unknown fan%d status 0x%x\n", i,
-			    sdata[r] & 0xff);
-			break;
-		}
-		ssc->ses_objmap[oid++].svalid = 1;
-		r++;
-	}
-
-	/*
-	 * No matter how you cut it, no cooling elements when there
-	 * should be some there is critical.
-	 */
-	if (cc->Nfans && nitems == 0) {
-		ssc->ses_encstat |= SES_ENCSTAT_CRITICAL;
-	}
-
-
-	for (i = 0; i < cc->Npwr; i++) {
-		SAFT_BAIL(r, hiwater, sdata, buflen);
-		ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNKNOWN;
-		ssc->ses_objmap[oid].encstat[1] = 0;	/* resvd */
-		ssc->ses_objmap[oid].encstat[2] = 0;	/* resvd */
-		ssc->ses_objmap[oid].encstat[3] = 0x20;	/* requested on */
-		switch ((uint8_t)sdata[r]) {
-		case 0x00:	/* pws operational and on */
-			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
-			break;
-		case 0x01:	/* pws operational and off */
-			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
-			ssc->ses_objmap[oid].encstat[3] = 0x10;
-			ssc->ses_encstat |= SES_ENCSTAT_INFO;
-			break;
-		case 0x10:	/* pws is malfunctioning and commanded on */
-			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_CRIT;
-			ssc->ses_objmap[oid].encstat[3] = 0x61;
-			ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL;
-			break;
-
-		case 0x11:	/* pws is malfunctioning and commanded off */
-			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_NONCRIT;
-			ssc->ses_objmap[oid].encstat[3] = 0x51;
-			ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL;
-			break;
-		case 0x20:	/* pws is not present */
-			ssc->ses_objmap[oid].encstat[0] =
-			    SES_OBJSTAT_NOTINSTALLED;
-			ssc->ses_objmap[oid].encstat[3] = 0;
-			ssc->ses_encstat |= SES_ENCSTAT_INFO;
-			break;
-		case 0x21:	/* pws is present */
-			/*
-			 * This is for enclosures that cannot tell whether the
-			 * device is on or malfunctioning, but know that it is
-			 * present. Just fall through.
-			 */
-			/* FALLTHROUGH */
-		case 0x80:	/* Unknown or Not Reportable Status */
-			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNKNOWN;
-			ssc->ses_objmap[oid].encstat[3] = 0;
-			ssc->ses_encstat |= SES_ENCSTAT_INFO;
-			break;
-		default:
-			SES_LOG(ssc, "unknown power supply %d status (0x%x)\n",
-			    i, sdata[r] & 0xff);
-			break;
-		}
-		ssc->ses_objmap[oid++].svalid = 1;
-		r++;
-	}
-
-	/*
-	 * Skip over Slot SCSI IDs
-	 */
-	r += cc->Nslots;
-
-	/*
-	 * We always have doorlock status, no matter what,
-	 * but we only save the status if we have one.
-	 */
-	SAFT_BAIL(r, hiwater, sdata, buflen);
-	if (cc->DoorLock) {
-		/*
-		 * 0 = Door Locked
-		 * 1 = Door Unlocked, or no Lock Installed
-		 * 0x80 = Unknown or Not Reportable Status
-		 */
-		ssc->ses_objmap[oid].encstat[1] = 0;
-		ssc->ses_objmap[oid].encstat[2] = 0;
-		switch ((uint8_t)sdata[r]) {
-		case 0:
-			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
-			ssc->ses_objmap[oid].encstat[3] = 0;
-			break;
-		case 1:
-			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
-			ssc->ses_objmap[oid].encstat[3] = 1;
-			break;
-		case 0x80:
-			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNKNOWN;
-			ssc->ses_objmap[oid].encstat[3] = 0;
-			ssc->ses_encstat |= SES_ENCSTAT_INFO;
-			break;
-		default:
-			ssc->ses_objmap[oid].encstat[0] =
-			    SES_OBJSTAT_UNSUPPORTED;
-			SES_LOG(ssc, "unknown lock status 0x%x\n",
-			    sdata[r] & 0xff);
-			break;
-		}
-		ssc->ses_objmap[oid++].svalid = 1;
-	}
-	r++;
-
-	/*
-	 * We always have speaker status, no matter what,
-	 * but we only save the status if we have one.
-	 */
-	SAFT_BAIL(r, hiwater, sdata, buflen);
-	if (cc->Nspkrs) {
-		ssc->ses_objmap[oid].encstat[1] = 0;
-		ssc->ses_objmap[oid].encstat[2] = 0;
-		if (sdata[r] == 1) {
-			/*
-			 * We need to cache tone urgency indicators.
-			 * Someday.
-			 */
-			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_NONCRIT;
-			ssc->ses_objmap[oid].encstat[3] = 0x8;
-			ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL;
-		} else if (sdata[r] == 0) {
-			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
-			ssc->ses_objmap[oid].encstat[3] = 0;
-		} else {
-			ssc->ses_objmap[oid].encstat[0] =
-			    SES_OBJSTAT_UNSUPPORTED;
-			ssc->ses_objmap[oid].encstat[3] = 0;
-			SES_LOG(ssc, "unknown spkr status 0x%x\n",
-			    sdata[r] & 0xff);
-		}
-		ssc->ses_objmap[oid++].svalid = 1;
-	}
-	r++;
-
-	for (i = 0; i < cc->Ntherm; i++) {
-		SAFT_BAIL(r, hiwater, sdata, buflen);
-		/*
-		 * Status is a range from -10 to 245 deg Celsius,
-		 * which we need to normalize to -20 to -245 according
-		 * to the latest SCSI spec, which makes little
-		 * sense since this would overflow an 8bit value.
-		 * Well, still, the base normalization is -20,
-		 * not -10, so we have to adjust.
-		 *
-		 * So what's over and under temperature?
-		 * Hmm- we'll state that 'normal' operating
-		 * is 10 to 40 deg Celsius.
-		 */
-
-		/*
-		 * Actually.... All of the units that people out in the world
-		 * seem to have do not come even close to setting a value that
-		 * complies with this spec.
-		 *
-		 * The closest explanation I could find was in an
-		 * LSI-Logic manual, which seemed to indicate that
-		 * this value would be set by whatever the I2C code
-		 * would interpolate from the output of an LM75
-		 * temperature sensor.
-		 *
-		 * This means that it is impossible to use the actual
-		 * numeric value to predict anything. But we don't want
-		 * to lose the value. So, we'll propagate the *uncorrected*
-		 * value and set SES_OBJSTAT_NOTAVAIL. We'll depend on the
-		 * temperature flags for warnings.
-		 */
-		ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_NOTAVAIL;
-		ssc->ses_objmap[oid].encstat[1] = 0;
-		ssc->ses_objmap[oid].encstat[2] = sdata[r];
-		ssc->ses_objmap[oid].encstat[3] = 0;
-		ssc->ses_objmap[oid++].svalid = 1;
-		r++;
-	}
-
-	/*
-	 * Now, for "pseudo" thermometers, we have two bytes
-	 * of information in enclosure status- 16 bits. Actually,
-	 * the MSB is a single TEMP ALERT flag indicating whether
-	 * any other bits are set, but, thanks to fuzzy thinking,
-	 * in the SAF-TE spec, this can also be set even if no
-	 * other bits are set, thus making this really another
-	 * binary temperature sensor.
-	 */
-
-	SAFT_BAIL(r, hiwater, sdata, buflen);
-	tempflags = sdata[r++];
-	SAFT_BAIL(r, hiwater, sdata, buflen);
-	tempflags |= (tempflags << 8) | sdata[r++];
-
-	for (i = 0; i < NPSEUDO_THERM; i++) {
-		ssc->ses_objmap[oid].encstat[1] = 0;
-		if (tempflags & (1 << (NPSEUDO_THERM - i - 1))) {
-			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_CRIT;
-			ssc->ses_objmap[4].encstat[2] = 0xff;
-			/*
-			 * Set 'over temperature' failure.
-			 */
-			ssc->ses_objmap[oid].encstat[3] = 8;
-			ssc->ses_encstat |= SES_ENCSTAT_CRITICAL;
-		} else {
-			/*
-			 * We used to say 'not available' and synthesize a
-			 * nominal 30 deg (C)- that was wrong. Actually,
-			 * Just say 'OK', and use the reserved value of
-			 * zero.
-			 */
-			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
-			ssc->ses_objmap[oid].encstat[2] = 0;
-			ssc->ses_objmap[oid].encstat[3] = 0;
-		}
-		ssc->ses_objmap[oid++].svalid = 1;
-	}
-
-	/*
-	 * Get alarm status.
-	 */
-	ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
-	ssc->ses_objmap[oid].encstat[3] = ssc->ses_objmap[oid].priv;
-	ssc->ses_objmap[oid++].svalid = 1;
-
-	/*
-	 * Now get drive slot status
-	 */
-	cdb[2] = SAFTE_RD_RDDSTS;
-	amt = buflen;
-	err = ses_runcmd(ssc, cdb, 10, sdata, &amt);
-	if (err) {
-		SES_FREE(sdata, buflen);
-		return (err);
-	}
-	hiwater = buflen - amt;
-	for (r = i = 0; i < cc->Nslots; i++, r += 4) {
-		SAFT_BAIL(r+3, hiwater, sdata, buflen);
-		ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNSUPPORTED;
-		ssc->ses_objmap[oid].encstat[1] = (uint8_t) i;
-		ssc->ses_objmap[oid].encstat[2] = 0;
-		ssc->ses_objmap[oid].encstat[3] = 0;
-		status = sdata[r+3];
-		if ((status & 0x1) == 0) {	/* no device */
-			ssc->ses_objmap[oid].encstat[0] =
-			    SES_OBJSTAT_NOTINSTALLED;
-		} else {
-			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
-		}
-		if (status & 0x2) {
-			ssc->ses_objmap[oid].encstat[2] = 0x8;
-		}
-		if ((status & 0x4) == 0) {
-			ssc->ses_objmap[oid].encstat[3] = 0x10;
-		}
-		ssc->ses_objmap[oid++].svalid = 1;
-	}
-	/* see comment below about sticky enclosure status */
-	ssc->ses_encstat |= ENCI_SVALID | oencstat;
-	SES_FREE(sdata, buflen);
-	return (0);
-}
-
-static int
-set_objstat_sel(ses_softc_t *ssc, ses_objstat *obp, int slp)
-{
-	int idx;
-	encobj *ep;
-	struct scfg *cc = ssc->ses_private;
-
-	if (cc == NULL)
-		return (0);
-
-	idx = (int)obp->obj_id;
-	ep = &ssc->ses_objmap[idx];
-
-	switch (ep->enctype) {
-	case SESTYP_DEVICE:
-		if (obp->cstat[0] & SESCTL_PRDFAIL) {
-			ep->priv |= 0x40;
-		}
-		/* SESCTL_RSTSWAP has no correspondence in SAF-TE */
-		if (obp->cstat[0] & SESCTL_DISABLE) {
-			ep->priv |= 0x80;
-			/*
-			 * Hmm. Try to set the 'No Drive' flag.
-			 * Maybe that will count as a 'disable'.
-			 */
-		}
-		if (ep->priv & 0xc6) {
-			ep->priv &= ~0x1;
-		} else {
-			ep->priv |= 0x1;	/* no errors */
-		}
-		wrslot_stat(ssc, slp);
-		break;
-	case SESTYP_POWER:
-		/*
-		 * Okay- the only one that makes sense here is to
-		 * do the 'disable' for a power supply.
-		 */
-		if (obp->cstat[0] & SESCTL_DISABLE) {
-			(void) wrbuf16(ssc, SAFTE_WT_ACTPWS,
-				idx - cc->pwroff, 0, 0, slp);
-		}
-		break;
-	case SESTYP_FAN:
-		/*
-		 * Okay- the only one that makes sense here is to
-		 * set fan speed to zero on disable.
-		 */
-		if (obp->cstat[0] & SESCTL_DISABLE) {
-			/* remember- fans are the first items, so idx works */
-			(void) wrbuf16(ssc, SAFTE_WT_FANSPD, idx, 0, 0, slp);
-		}
-		break;
-	case SESTYP_DOORLOCK:
-		/*
-		 * Well, we can 'disable' the lock.
-		 */
-		if (obp->cstat[0] & SESCTL_DISABLE) {
-			cc->flag2 &= ~SAFT_FLG2_LOCKDOOR;
-			(void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
-				cc->flag2, 0, slp);
-		}
-		break;
-	case SESTYP_ALARM:
-		/*
-		 * Well, we can 'disable' the alarm.
-		 */
-		if (obp->cstat[0] & SESCTL_DISABLE) {
-			cc->flag2 &= ~SAFT_FLG1_ALARM;
-			ep->priv |= 0x40;	/* Muted */
-			(void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
-				cc->flag2, 0, slp);
-		}
-		break;
-	default:
-		break;
-	}
-	ep->svalid = 0;
-	return (0);
-}
-
-/*
- * This function handles all of the 16 byte WRITE BUFFER commands.
- */
-static int
-wrbuf16(ses_softc_t *ssc, uint8_t op, uint8_t b1, uint8_t b2,
-    uint8_t b3, int slp)
-{
-	int err, amt;
-	char *sdata;
-	struct scfg *cc = ssc->ses_private;
-	static char cdb[10] = { WRITE_BUFFER, 1, 0, 0, 0, 0, 0, 0, 16, 0 };
-
-	if (cc == NULL)
-		return (0);
-
-	sdata = SES_MALLOC(16);
-	if (sdata == NULL)
-		return (ENOMEM);
-
-	SES_DLOG(ssc, "saf_wrbuf16 %x %x %x %x\n", op, b1, b2, b3);
-
-	sdata[0] = op;
-	sdata[1] = b1;
-	sdata[2] = b2;
-	sdata[3] = b3;
-	MEMZERO(&sdata[4], 12);
-	amt = -16;
-	err = ses_runcmd(ssc, cdb, 10, sdata, &amt);
-	SES_FREE(sdata, 16);
-	return (err);
-}
-
-/*
- * This function updates the status byte for the device slot described.
- *
- * Since this is an optional SAF-TE command, there's no point in
- * returning an error.
- */
-static void
-wrslot_stat(ses_softc_t *ssc, int slp)
-{
-	int i, amt;
-	encobj *ep;
-	char cdb[10], *sdata;
-	struct scfg *cc = ssc->ses_private;
-
-	if (cc == NULL)
-		return;
-
-	SES_DLOG(ssc, "saf_wrslot\n");
-	cdb[0] = WRITE_BUFFER;
-	cdb[1] = 1;
-	cdb[2] = 0;
-	cdb[3] = 0;
-	cdb[4] = 0;
-	cdb[5] = 0;
-	cdb[6] = 0;
-	cdb[7] = 0;
-	cdb[8] = cc->Nslots * 3 + 1;
-	cdb[9] = 0;
-
-	sdata = SES_MALLOC(cc->Nslots * 3 + 1);
-	if (sdata == NULL)
-		return;
-	MEMZERO(sdata, cc->Nslots * 3 + 1);
-
-	sdata[0] = SAFTE_WT_DSTAT;
-	for (i = 0; i < cc->Nslots; i++) {
-		ep = &ssc->ses_objmap[cc->slotoff + i];
-		SES_DLOG(ssc, "saf_wrslot %d <- %x\n", i, ep->priv & 0xff);
-		sdata[1 + (3 * i)] = ep->priv & 0xff;
-	}
-	amt = -(cc->Nslots * 3 + 1);
-	(void) ses_runcmd(ssc, cdb, 10, sdata, &amt);
-	SES_FREE(sdata, cc->Nslots * 3 + 1);
-}
-
-/*
- * This function issues the "PERFORM SLOT OPERATION" command.
- */
-static int
-perf_slotop(ses_softc_t *ssc, uint8_t slot, uint8_t opflag, int slp)
-{
-	int err, amt;
-	char *sdata;
-	struct scfg *cc = ssc->ses_private;
-	static char cdb[10] =
-	    { WRITE_BUFFER, 1, 0, 0, 0, 0, 0, 0, SAFT_SCRATCH, 0 };
-
-	if (cc == NULL)
-		return (0);
-
-	sdata = SES_MALLOC(SAFT_SCRATCH);
-	if (sdata == NULL)
-		return (ENOMEM);
-	MEMZERO(sdata, SAFT_SCRATCH);
-
-	sdata[0] = SAFTE_WT_SLTOP;
-	sdata[1] = slot;
-	sdata[2] = opflag;
-	SES_DLOG(ssc, "saf_slotop slot %d op %x\n", slot, opflag);
-	amt = -SAFT_SCRATCH;
-	err = ses_runcmd(ssc, cdb, 10, sdata, &amt);
-	SES_FREE(sdata, SAFT_SCRATCH);
-	return (err);
-}
diff -r 99650cb861f2 -r 58b18bd1429e head/sys/cam/scsi/scsi_ses.h
--- a/head/sys/cam/scsi/scsi_ses.h	Wed Jul 25 16:42:35 2012 +0300
+++ b/head/sys/cam/scsi/scsi_ses.h	Wed Jul 25 16:45:04 2012 +0300
@@ -1,4 +1,4 @@
-/* $FreeBSD: head/sys/cam/scsi/scsi_ses.h 222339 2011-05-27 03:44:47Z mav $ */
+/* $FreeBSD: head/sys/cam/scsi/scsi_ses.h 238740 2012-07-24 13:32:49Z mav $ */
 /*-
  * Copyright (c) 2000 by Matthew Jacob
  * All rights reserved.
@@ -29,107 +29,2131 @@
  *
  */
 
-#define	SESIOC			('s' - 040)
-#define	SESIOC_GETNOBJ		_IO(SESIOC, 1)
-#define	SESIOC_GETOBJMAP	_IO(SESIOC, 2)
-#define	SESIOC_GETENCSTAT	_IO(SESIOC, 3)
-#define	SESIOC_SETENCSTAT	_IO(SESIOC, 4)
-#define	SESIOC_GETOBJSTAT	_IO(SESIOC, 5)
-#define	SESIOC_SETOBJSTAT	_IO(SESIOC, 6)
-#define	SESIOC_GETTEXT		_IO(SESIOC, 7)
-#define	SESIOC_INIT		_IO(SESIOC, 8)
+#ifndef	_SCSI_SES_H_
+#define	_SCSI_SES_H_
 
+#include <cam/scsi/scsi_all.h>
+
+/*========================== Field Extraction Macros =========================*/
+#define MK_ENUM(S, F, SUFFIX) S ## _ ## F ## SUFFIX
+
+#define GEN_GETTER(LS, US, LF, UF)					    \
+static inline int							    \
+LS ## _get_ ## LF(struct LS *elem) {					    \
+	return ((elem->bytes[MK_ENUM(US,UF,_BYTE)] & MK_ENUM(US,UF,_MASK))  \
+	     >> MK_ENUM(US,UF,_SHIFT));					    \
+}
+
+#define GEN_SETTER(LS, US, LF, UF)					    \
+static inline void							    \
+LS ## _set_ ## LF(struct LS *elem, int val) {				    \
+	elem->bytes[MK_ENUM(US,UF,_BYTE)] &= ~MK_ENUM(US,UF,_MASK);	    \
+	elem->bytes[MK_ENUM(US,UF,_BYTE)] |=				    \
+	    (val << MK_ENUM(US,UF,_SHIFT)) & MK_ENUM(US,UF,_MASK);	    \
+}
+
+#define GEN_HDR_GETTER(LS, US, LF, UF)					    \
+static inline int							    \
+LS ## _get_ ## LF(struct LS *page) {					    \
+	return ((page->hdr.page_specific_flags & MK_ENUM(US,UF,_MASK))	    \
+	     >> MK_ENUM(US,UF,_SHIFT));					    \
+}
+
+#define GEN_HDR_SETTER(LS, US, LF, UF)					    \
+static inline void							    \
+LS ## _set_ ## LF(struct LS *page, int val) {				    \
+	page->hdr.page_specific_flags &= ~MK_ENUM(US,UF,_MASK);		    \
+	page->hdr.page_specific_flags |=				    \
+	    (val << MK_ENUM(US,UF,_SHIFT)) & MK_ENUM(US,UF,_MASK);	    \
+}
+
+#define GEN_ACCESSORS(LS, US, LF, UF)					    \
+GEN_GETTER(LS, US, LF, UF)						    \
+GEN_SETTER(LS, US, LF, UF)
+
+#define GEN_HDR_ACCESSORS(LS, US, LF, UF)				    \
+GEN_HDR_GETTER(LS, US, LF, UF)						    \
+GEN_HDR_SETTER(LS, US, LF, UF)
+
+/*===============  Common SCSI ENC Diagnostic Page Structures ===============*/
+struct ses_page_hdr {
+	uint8_t page_code;
+	uint8_t page_specific_flags;
+	uint8_t length[2];
+	uint8_t gen_code[4];
+};
+
+static inline size_t
+ses_page_length(const struct ses_page_hdr *hdr)
+{
+	/*
+	 * The page length as received only accounts for bytes that
+	 * follow the length field, namely starting with the generation
+	 * code field.
+	 */
+	return (scsi_2btoul(hdr->length)
+	      + offsetof(struct ses_page_hdr, gen_code));
+}
+
+/*============= SCSI ENC Configuration Diagnostic Page Structures ============*/
+struct ses_enc_desc {
+	uint8_t byte0;
+	/*
+	 * reserved0	: 1,
+	 * rel_id	: 3,	relative enclosure process id
+	 * reserved1	: 1,
+	 * num_procs	: 3;	number of enclosure procesenc
+	 */
+	uint8_t	subenc_id;	/* Sub-enclosure Identifier */
+	uint8_t	num_types;	/* # of supported types */
+	uint8_t	length;		/* Enclosure Descriptor Length */
+	uint8_t	logical_id[8];	/* formerly wwn */
+	uint8_t	vendor_id[8];
+	uint8_t	product_id[16];
+	uint8_t	product_rev[4];
+	uint8_t vendor_bytes[];
+};
+
+static inline uint8_t *
+ses_enc_desc_last_byte(struct ses_enc_desc *encdesc)
+{
+	return (&encdesc->length + encdesc->length);
+}
+
+static inline struct ses_enc_desc *
+ses_enc_desc_next(struct ses_enc_desc *encdesc)
+{
+	return ((struct ses_enc_desc *)(ses_enc_desc_last_byte(encdesc) + 1));
+}
+
+static inline int
+ses_enc_desc_is_complete(struct ses_enc_desc *encdesc, uint8_t *last_buf_byte)
+{
+	return (&encdesc->length <= last_buf_byte
+	     && ses_enc_desc_last_byte(encdesc) <= last_buf_byte);
+}
+
+struct ses_elm_type_desc {
+	uint8_t	etype_elm_type;	/* type of element */
+	uint8_t	etype_maxelt;	/* maximum supported */
+	uint8_t	etype_subenc;	/* in sub-enclosure #n */
+	uint8_t	etype_txt_len;	/* Type Descriptor Text Length */
+};
+
+struct ses_cfg_page {
+	struct ses_page_hdr hdr;
+	struct ses_enc_desc subencs[];
+	/* type descriptors */
+	/* type text */
+};
+
+static inline int
+ses_cfg_page_get_num_subenc(struct ses_cfg_page *page)
+{
+	return (page->hdr.page_specific_flags + 1);
+}
+
+
+/*================ SCSI SES Control Diagnostic Page Structures ==============*/
+struct ses_ctrl_common {
+	uint8_t bytes[1];
+};
+
+enum ses_ctrl_common_field_data {
+	SES_CTRL_COMMON_SELECT_BYTE		= 0,
+	SES_CTRL_COMMON_SELECT_MASK		= 0x80,
+	SES_CTRL_COMMON_SELECT_SHIFT		= 7,
+
+	SES_CTRL_COMMON_PRDFAIL_BYTE		= 0,
+	SES_CTRL_COMMON_PRDFAIL_MASK		= 0x40,
+	SES_CTRL_COMMON_PRDFAIL_SHIFT		= 6,
+
+	SES_CTRL_COMMON_DISABLE_BYTE		= 0,
+	SES_CTRL_COMMON_DISABLE_MASK		= 0x20,
+	SES_CTRL_COMMON_DISABLE_SHIFT		= 5,
+
+	SES_CTRL_COMMON_RST_SWAP_BYTE		= 0,
+	SES_CTRL_COMMON_RST_SWAP_MASK		= 0x10,
+	SES_CTRL_COMMON_RST_SWAP_SHIFT		= 4
+};
+
+#define GEN_SES_CTRL_COMMON_ACCESSORS(LCASE, UCASE) \
+    GEN_ACCESSORS(ses_ctrl_common, SES_CTRL_COMMON, LCASE, UCASE)
+GEN_SES_CTRL_COMMON_ACCESSORS(select,   SELECT)
+GEN_SES_CTRL_COMMON_ACCESSORS(prdfail,  PRDFAIL)
+GEN_SES_CTRL_COMMON_ACCESSORS(disable,  DISABLE)
+GEN_SES_CTRL_COMMON_ACCESSORS(rst_swap, RST_SWAP)
+#undef GEN_SES_CTRL_COMMON_ACCESSORS
+
+/*------------------------ Device Slot Control Element ----------------------*/
+struct ses_ctrl_dev_slot {
+	struct ses_ctrl_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_ctrl_dev_slot_field_data {
+	SES_CTRL_DEV_SLOT_RQST_ACTIVE_BYTE	= 1,
+	SES_CTRL_DEV_SLOT_RQST_ACTIVE_MASK	= 0x80,
+	SES_CTRL_DEV_SLOT_RQST_ACTIVE_SHIFT	= 7,
+
+	SES_CTRL_DEV_SLOT_DO_NOT_REMOVE_BYTE	= 1,
+	SES_CTRL_DEV_SLOT_DO_NOT_REMOVE_MASK	= 0x40,
+	SES_CTRL_DEV_SLOT_DO_NOT_REMOVE_SHIFT	= 6,
+
+	SES_CTRL_DEV_SLOT_RQST_MISSING_BYTE	= 1,
+	SES_CTRL_DEV_SLOT_RQST_MISSING_MASK	= 0x10,
+	SES_CTRL_DEV_SLOT_RQST_MISSING_SHIFT	= 4,
+
+	SES_CTRL_DEV_SLOT_RQST_INSERT_BYTE	= 1,
+	SES_CTRL_DEV_SLOT_RQST_INSERT_MASK	= 0x08,
+	SES_CTRL_DEV_SLOT_RQST_INSERT_SHIFT	= 3,
+
+	SES_CTRL_DEV_SLOT_RQST_REMOVE_BYTE	= 1,
+	SES_CTRL_DEV_SLOT_RQST_REMOVE_MASK	= 0x04,
+	SES_CTRL_DEV_SLOT_RQST_REMOVE_SHIFT	= 2,
+
+	SES_CTRL_DEV_SLOT_RQST_IDENT_BYTE	= 1,
+	SES_CTRL_DEV_SLOT_RQST_IDENT_MASK	= 0x02,
+	SES_CTRL_DEV_SLOT_RQST_IDENT_SHIFT	= 1,
+
+	SES_CTRL_DEV_SLOT_RQST_FAULT_BYTE	= 2,
+	SES_CTRL_DEV_SLOT_RQST_FAULT_MASK	= 0x20,
+	SES_CTRL_DEV_SLOT_RQST_FAULT_SHIFT	= 5,
+
+	SES_CTRL_DEV_SLOT_DEVICE_OFF_BYTE	= 2,
+	SES_CTRL_DEV_SLOT_DEVICE_OFF_MASK	= 0x10,
+	SES_CTRL_DEV_SLOT_DEVICE_OFF_SHIFT	= 4,
+
+	SES_CTRL_DEV_SLOT_ENABLE_BYP_A_BYTE	= 2,
+	SES_CTRL_DEV_SLOT_ENABLE_BYP_A_MASK	= 0x08,
+	SES_CTRL_DEV_SLOT_ENABLE_BYP_A_SHIFT	= 3,
+
+	SES_CTRL_DEV_SLOT_ENABLE_BYP_B_BYTE	= 2,
+	SES_CTRL_DEV_SLOT_ENABLE_BYP_B_MASK	= 0x04,
+	SES_CTRL_DEV_SLOT_ENABLE_BYP_B_SHIFT	= 2
+};
+#define GEN_SES_CTRL_DEV_SLOT_ACCESSORS(LCASE, UCASE) \
+    GEN_ACCESSORS(ses_ctrl_dev_slot, SES_CTRL_DEV_SLOT, LCASE, UCASE)
+
+GEN_SES_CTRL_DEV_SLOT_ACCESSORS(rqst_active,   RQST_ACTIVE)
+GEN_SES_CTRL_DEV_SLOT_ACCESSORS(do_not_remove, DO_NOT_REMOVE)
+GEN_SES_CTRL_DEV_SLOT_ACCESSORS(rqst_missing,  RQST_MISSING)
+GEN_SES_CTRL_DEV_SLOT_ACCESSORS(rqst_insert,   RQST_INSERT)
+GEN_SES_CTRL_DEV_SLOT_ACCESSORS(rqst_remove,   RQST_REMOVE)
+GEN_SES_CTRL_DEV_SLOT_ACCESSORS(rqst_ident,    RQST_IDENT)
+GEN_SES_CTRL_DEV_SLOT_ACCESSORS(rqst_fault,    RQST_FAULT)
+GEN_SES_CTRL_DEV_SLOT_ACCESSORS(device_off,    DEVICE_OFF)
+GEN_SES_CTRL_DEV_SLOT_ACCESSORS(enable_byp_a,  ENABLE_BYP_A)
+GEN_SES_CTRL_DEV_SLOT_ACCESSORS(enable_byp_b,  ENABLE_BYP_B)
+#undef GEN_SES_CTRL_DEV_SLOT_ACCESSORS
+
+/*--------------------- Array Device Slot Control Element --------------------*/
+struct ses_ctrl_array_dev_slot {
+	struct ses_ctrl_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_ctrl_array_dev_slot_field_data {
+	SES_CTRL_ARRAY_DEV_SLOT_RQST_OK_BYTE			= 0,
+	SES_CTRL_ARRAY_DEV_SLOT_RQST_OK_MASK			= 0x80,
+	SES_CTRL_ARRAY_DEV_SLOT_RQST_OK_SHIFT			= 7,
+
+	SES_CTRL_ARRAY_DEV_SLOT_RQST_RSVD_DEVICE_BYTE		= 0,
+	SES_CTRL_ARRAY_DEV_SLOT_RQST_RSVD_DEVICE_MASK		= 0x40,
+	SES_CTRL_ARRAY_DEV_SLOT_RQST_RSVD_DEVICE_SHIFT		= 6,
+
+	SES_CTRL_ARRAY_DEV_SLOT_RQST_HOT_SPARE_BYTE		= 0,
+	SES_CTRL_ARRAY_DEV_SLOT_RQST_HOT_SPARE_MASK		= 0x20,
+	SES_CTRL_ARRAY_DEV_SLOT_RQST_HOT_SPARE_SHIFT		= 5,
+
+	SES_CTRL_ARRAY_DEV_SLOT_RQST_CONS_CHECK_BYTE		= 0,
+	SES_CTRL_ARRAY_DEV_SLOT_RQST_CONS_CHECK_MASK		= 0x10,
+	SES_CTRL_ARRAY_DEV_SLOT_RQST_CONS_CHECK_SHIFT		= 4,
+
+	SES_CTRL_ARRAY_DEV_SLOT_RQST_IN_CRIT_ARRAY_BYTE		= 0,
+	SES_CTRL_ARRAY_DEV_SLOT_RQST_IN_CRIT_ARRAY_MASK		= 0x08,
+	SES_CTRL_ARRAY_DEV_SLOT_RQST_IN_CRIT_ARRAY_SHIFT	= 3,
+
+	SES_CTRL_ARRAY_DEV_SLOT_RQST_IN_FAILED_ARRAY_BYTE	= 0,
+	SES_CTRL_ARRAY_DEV_SLOT_RQST_IN_FAILED_ARRAY_MASK	= 0x04,
+	SES_CTRL_ARRAY_DEV_SLOT_RQST_IN_FAILED_ARRAY_SHIFT	= 2,
+
+	SES_CTRL_ARRAY_DEV_SLOT_RQST_REBUILD_REMAP_BYTE		= 0,
+	SES_CTRL_ARRAY_DEV_SLOT_RQST_REBUILD_REMAP_MASK		= 0x02,
+	SES_CTRL_ARRAY_DEV_SLOT_RQST_REBUILD_REMAP_SHIFT	= 1,
+
+	SES_CTRL_ARRAY_DEV_SLOT_RQST_REBUILD_REMAP_ABORT_BYTE	= 0,
+	SES_CTRL_ARRAY_DEV_SLOT_RQST_REBUILD_REMAP_ABORT_MASK	= 0x01,
+	SES_CTRL_ARRAY_DEV_SLOT_RQST_REBUILD_REMAP_ABORT_SHIFT	= 0
+
+	/*
+	 * The remaining fields are identical to the device
+	 * slot element type.  Access them through the device slot
+	 * element type and its accessors.
+	 */
+};
+#define GEN_SES_CTRL_ARRAY_DEV_SLOT_ACCESSORS(LCASE, UCASE)		\
+    GEN_ACCESSORS(ses_ctrl_array_dev_slot, SES_CTRL_ARRAY_DEV_SLOT,	\
+		  LCASE, UCASE)
+GEN_SES_CTRL_ARRAY_DEV_SLOT_ACCESSORS(rqst_ok,             RQST_OK)
+GEN_SES_CTRL_ARRAY_DEV_SLOT_ACCESSORS(rqst_rsvd_device,    RQST_RSVD_DEVICE)
+GEN_SES_CTRL_ARRAY_DEV_SLOT_ACCESSORS(rqst_hot_spare,      RQST_HOT_SPARE)
+GEN_SES_CTRL_ARRAY_DEV_SLOT_ACCESSORS(rqst_cons_check,     RQST_CONS_CHECK)
+GEN_SES_CTRL_ARRAY_DEV_SLOT_ACCESSORS(rqst_in_crit_array,  RQST_IN_CRIT_ARRAY)
+GEN_SES_CTRL_ARRAY_DEV_SLOT_ACCESSORS(rqst_in_failed_array,
+				      RQST_IN_FAILED_ARRAY)
+GEN_SES_CTRL_ARRAY_DEV_SLOT_ACCESSORS(rqst_rebuild_remap,  RQST_REBUILD_REMAP)
+GEN_SES_CTRL_ARRAY_DEV_SLOT_ACCESSORS(rqst_rebuild_remap_abort,
+				      RQST_REBUILD_REMAP_ABORT)
+#undef GEN_SES_CTRL_ARRAY_DEV_SLOT_ACCESSORS
+
+/*----------------------- Power Supply Control Element -----------------------*/
+struct ses_ctrl_power_supply {
+	struct ses_ctrl_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_ctrl_power_supply_field_data {
+	SES_CTRL_POWER_SUPPLY_RQST_IDENT_BYTE	= 0,
+	SES_CTRL_POWER_SUPPLY_RQST_IDENT_MASK	= 0x80,
+	SES_CTRL_POWER_SUPPLY_RQST_IDENT_SHIFT	= 7,
+
+	SES_CTRL_POWER_SUPPLY_RQST_FAIL_BYTE	= 2,
+	SES_CTRL_POWER_SUPPLY_RQST_FAIL_MASK	= 0x40,
+	SES_CTRL_POWER_SUPPLY_RQST_FAIL_SHIFT	= 6,
+
+	SES_CTRL_POWER_SUPPLY_RQST_ON_BYTE	= 2,
+	SES_CTRL_POWER_SUPPLY_RQST_ON_MASK	= 0x20,
+	SES_CTRL_POWER_SUPPLY_RQST_ON_SHIFT	= 5
+};
+
+#define GEN_SES_CTRL_POWER_SUPPLY_ACCESSORS(LCASE, UCASE)	\
+    GEN_ACCESSORS(ses_ctrl_power_supply, SES_CTRL_POWER_SUPPLY, LCASE, UCASE)
+GEN_SES_CTRL_POWER_SUPPLY_ACCESSORS(rqst_ident, RQST_IDENT)
+GEN_SES_CTRL_POWER_SUPPLY_ACCESSORS(rqst_fail,  RQST_FAIL)
+GEN_SES_CTRL_POWER_SUPPLY_ACCESSORS(rqst_on,    RQST_ON)
+#undef GEN_SES_CTRL_POWER_SUPPLY_ACCESSORS
+
+/*-------------------------- Cooling Control Element -------------------------*/
+struct ses_ctrl_cooling {
+	struct ses_ctrl_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_ctrl_cooling_field_data {
+	SES_CTRL_COOLING_RQST_IDENT_BYTE		= 0,
+	SES_CTRL_COOLING_RQST_IDENT_MASK		= 0x80,
+	SES_CTRL_COOLING_RQST_IDENT_SHIFT		= 7,
+
+	SES_CTRL_COOLING_RQST_FAIL_BYTE			= 2,
+	SES_CTRL_COOLING_RQST_FAIL_MASK			= 0x40,
+	SES_CTRL_COOLING_RQST_FAIL_SHIFT		= 6,
+
+	SES_CTRL_COOLING_RQST_ON_BYTE			= 2,
+	SES_CTRL_COOLING_RQST_ON_MASK			= 0x20,
+	SES_CTRL_COOLING_RQST_ON_SHIFT			= 5,
+
+	SES_CTRL_COOLING_RQSTED_SPEED_CODE_BYTE		= 2,
+	SES_CTRL_COOLING_RQSTED_SPEED_CODE_MASK		= 0x07,
+	SES_CTRL_COOLING_RQSTED_SPEED_CODE_SHIFT	= 2,
+	SES_CTRL_COOLING_RQSTED_SPEED_CODE_UNCHANGED	= 0x00,
+	SES_CTRL_COOLING_RQSTED_SPEED_CODE_LOWEST	= 0x01,
+	SES_CTRL_COOLING_RQSTED_SPEED_CODE_HIGHEST	= 0x07
+};
+
+#define GEN_SES_CTRL_COOLING_ACCESSORS(LCASE, UCASE)	\
+    GEN_ACCESSORS(ses_ctrl_cooling, SES_CTRL_COOLING, LCASE, UCASE)
+GEN_SES_CTRL_COOLING_ACCESSORS(rqst_ident,        RQST_IDENT)
+GEN_SES_CTRL_COOLING_ACCESSORS(rqst_fail,         RQST_FAIL)
+GEN_SES_CTRL_COOLING_ACCESSORS(rqst_on,           RQST_ON)
+GEN_SES_CTRL_COOLING_ACCESSORS(rqsted_speed_code, RQSTED_SPEED_CODE)
+#undef GEN_SES_CTRL_COOLING_ACCESSORS
+
+/*-------------------- Temperature Sensor Control Element --------------------*/
+struct ses_ctrl_temp_sensor {
+	struct ses_ctrl_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_ctrl_temp_sensor_field_data {
+	SES_CTRL_TEMP_SENSOR_RQST_IDENT_BYTE	= 0,
+	SES_CTRL_TEMP_SENSOR_RQST_IDENT_MASK	= 0x80,
+	SES_CTRL_TEMP_SENSOR_RQST_IDENT_SHIFT	= 7,
+
+	SES_CTRL_TEMP_SENSOR_RQST_FAIL_BYTE	= 0,
+	SES_CTRL_TEMP_SENSOR_RQST_FAIL_MASK	= 0x40,
+	SES_CTRL_TEMP_SENSOR_RQST_FAIL_SHIFT	= 6
+};
+
+#define GEN_SES_CTRL_TEMP_SENSOR_ACCESSORS(LCASE, UCASE)	\
+    GEN_ACCESSORS(ses_ctrl_temp_sensor, SES_CTRL_TEMP_SENSOR, LCASE, UCASE)
+GEN_SES_CTRL_TEMP_SENSOR_ACCESSORS(rqst_ident, RQST_IDENT)
+GEN_SES_CTRL_TEMP_SENSOR_ACCESSORS(rqst_fail,  RQST_FAIL)
+#undef GEN_SES_CTRL_TEMP_SENSOR_ACCESSORS
+
+/*------------------------- Door Lock Control Element ------------------------*/
+struct ses_ctrl_door_lock {
+	struct ses_ctrl_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_ctrl_door_lock_field_data {
+	SES_CTRL_DOOR_LOCK_RQST_IDENT_BYTE	= 0,
+	SES_CTRL_DOOR_LOCK_RQST_IDENT_MASK	= 0x80,
+	SES_CTRL_DOOR_LOCK_RQST_IDENT_SHIFT	= 7,
+
+	SES_CTRL_DOOR_LOCK_RQST_FAIL_BYTE	= 0,
+	SES_CTRL_DOOR_LOCK_RQST_FAIL_MASK	= 0x40,
+	SES_CTRL_DOOR_LOCK_RQST_FAIL_SHIFT	= 6,
+
+	SES_CTRL_DOOR_LOCK_UNLOCK_BYTE		= 2,
+	SES_CTRL_DOOR_LOCK_UNLOCK_MASK		= 0x01,
+	SES_CTRL_DOOR_LOCK_UNLOCK_SHIFT		= 0
+};
+
+#define GEN_SES_CTRL_DOOR_LOCK_ACCESSORS(LCASE, UCASE)	\
+    GEN_ACCESSORS(ses_ctrl_door_lock, SES_CTRL_DOOR_LOCK, LCASE, UCASE)
+GEN_SES_CTRL_DOOR_LOCK_ACCESSORS(rqst_ident, RQST_IDENT)
+GEN_SES_CTRL_DOOR_LOCK_ACCESSORS(rqst_fail,  RQST_FAIL)
+GEN_SES_CTRL_DOOR_LOCK_ACCESSORS(unlock,     UNLOCK)
+#undef GEN_SES_CTRL_DOOR_LOCK_ACCESSORS
+
+/*----------------------- Audible Alarm Control Element ----------------------*/
+struct ses_ctrl_audible_alarm {
+	struct ses_ctrl_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_ctrl_audible_alarm_field_data {
+	SES_CTRL_AUDIBLE_ALARM_RQST_IDENT_BYTE		= 0,
+	SES_CTRL_AUDIBLE_ALARM_RQST_IDENT_MASK		= 0x80,
+	SES_CTRL_AUDIBLE_ALARM_RQST_IDENT_SHIFT		= 7,
+
+	SES_CTRL_AUDIBLE_ALARM_RQST_FAIL_BYTE		= 0,
+	SES_CTRL_AUDIBLE_ALARM_RQST_FAIL_MASK		= 0x40,
+	SES_CTRL_AUDIBLE_ALARM_RQST_FAIL_SHIFT		= 6,
+
+	SES_CTRL_AUDIBLE_ALARM_SET_MUTE_BYTE		= 2,
+	SES_CTRL_AUDIBLE_ALARM_SET_MUTE_MASK		= 0x40,
+	SES_CTRL_AUDIBLE_ALARM_SET_MUTE_SHIFT		= 6,
+
+	SES_CTRL_AUDIBLE_ALARM_SET_REMIND_BYTE		= 2,
+	SES_CTRL_AUDIBLE_ALARM_SET_REMIND_MASK		= 0x10,
+	SES_CTRL_AUDIBLE_ALARM_SET_REMIND_SHIFT		= 4,
+
+	SES_CTRL_AUDIBLE_ALARM_TONE_CONTROL_BYTE	= 2,
+	SES_CTRL_AUDIBLE_ALARM_TONE_CONTROL_MASK	= 0x0F,
+	SES_CTRL_AUDIBLE_ALARM_TONE_CONTROL_SHIFT	= 0,
+	SES_CTRL_AUDIBLE_ALARM_TONE_CONTROL_INFO	= 0x08,
+	SES_CTRL_AUDIBLE_ALARM_TONE_CONTROL_NON_CRIT	= 0x04,
+	SES_CTRL_AUDIBLE_ALARM_TONE_CONTROL_CRIT	= 0x02,
+	SES_CTRL_AUDIBLE_ALARM_TONE_CONTROL_UNRECOV	= 0x01
+};
+
+#define GEN_SES_CTRL_AUDIBLE_ALARM_ACCESSORS(LCASE, UCASE)	\
+    GEN_ACCESSORS(ses_ctrl_audible_alarm, SES_CTRL_AUDIBLE_ALARM, LCASE, UCASE)
+GEN_SES_CTRL_AUDIBLE_ALARM_ACCESSORS(rqst_ident,   RQST_IDENT)
+GEN_SES_CTRL_AUDIBLE_ALARM_ACCESSORS(rqst_fail,    RQST_FAIL)
+GEN_SES_CTRL_AUDIBLE_ALARM_ACCESSORS(set_mute,     SET_MUTE)
+GEN_SES_CTRL_AUDIBLE_ALARM_ACCESSORS(set_remind,   SET_REMIND)
+GEN_SES_CTRL_AUDIBLE_ALARM_ACCESSORS(tone_control, TONE_CONTROL)
+#undef GEN_SES_CTRL_AUDIBLE_ALARM_ACCESSORS
+
+/*--------- Enclosure Services Controller Electronics Control Element --------*/
+struct ses_ctrl_ecc_electronics {
+	struct ses_ctrl_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_ctrl_ecc_electronics_field_data {
+	SES_CTRL_ECC_ELECTRONICS_RQST_IDENT_BYTE	= 0,
+	SES_CTRL_ECC_ELECTRONICS_RQST_IDENT_MASK	= 0x80,
+	SES_CTRL_ECC_ELECTRONICS_RQST_IDENT_SHIFT	= 7,
+
+	SES_CTRL_ECC_ELECTRONICS_RQST_FAIL_BYTE		= 0,
+	SES_CTRL_ECC_ELECTRONICS_RQST_FAIL_MASK		= 0x40,
+	SES_CTRL_ECC_ELECTRONICS_RQST_FAIL_SHIFT	= 6,
+
+	SES_CTRL_ECC_ELECTRONICS_SELECT_ELEMENT_BYTE	= 1,
+	SES_CTRL_ECC_ELECTRONICS_SELECT_ELEMENT_MASK	= 0x01,
+	SES_CTRL_ECC_ELECTRONICS_SELECT_ELEMENT_SHIFT	= 0
+};
+
+#define GEN_SES_CTRL_ECC_ELECTRONICS_ACCESSORS(LCASE, UCASE)		\
+    GEN_ACCESSORS(ses_ctrl_ecc_electronics, SES_CTRL_ECC_ELECTRONICS,	\
+		  LCASE, UCASE)
+GEN_SES_CTRL_ECC_ELECTRONICS_ACCESSORS(rqst_ident,     RQST_IDENT)
+GEN_SES_CTRL_ECC_ELECTRONICS_ACCESSORS(rqst_fail,      RQST_FAIL)
+GEN_SES_CTRL_ECC_ELECTRONICS_ACCESSORS(select_element, SELECT_ELEMENT)
+#undef GEN_SES_CTRL_ECC_ELECTRONICS_ACCESSORS
+
+/*----------- SCSI Services Controller Electronics Control Element -----------*/
+struct ses_ctrl_scc_electronics {
+	struct ses_ctrl_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_ctrl_scc_electronics_field_data {
+	SES_CTRL_SCC_ELECTRONICS_RQST_IDENT_BYTE	= 0,
+	SES_CTRL_SCC_ELECTRONICS_RQST_IDENT_MASK	= 0x80,
+	SES_CTRL_SCC_ELECTRONICS_RQST_IDENT_SHIFT	= 7,
+
+	SES_CTRL_SCC_ELECTRONICS_RQST_FAIL_BYTE		= 0,
+	SES_CTRL_SCC_ELECTRONICS_RQST_FAIL_MASK		= 0x40,
+	SES_CTRL_SCC_ELECTRONICS_RQST_FAIL_SHIFT	= 6
+};
+
+#define GEN_SES_CTRL_SCC_ELECTRONICS_ACCESSORS(LCASE, UCASE)		\
+    GEN_ACCESSORS(ses_ctrl_scc_electronics, SES_CTRL_SCC_ELECTRONICS,	\
+		  LCASE, UCASE)
+GEN_SES_CTRL_SCC_ELECTRONICS_ACCESSORS(rqst_ident, RQST_IDENT)
+GEN_SES_CTRL_SCC_ELECTRONICS_ACCESSORS(rqst_fail,  RQST_FAIL)
+#undef GEN_SES_CTRL_SCC_ELECTRONICS_ACCESSORS
+
+/*--------------------- Nonvolatile Cache Control Element --------------------*/
+struct ses_ctrl_nv_cache {
+	struct ses_ctrl_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_ctrl_nv_cache_field_data {
+	SES_CTRL_NV_CACHE_RQST_IDENT_BYTE	= 0,
+	SES_CTRL_NV_CACHE_RQST_IDENT_MASK	= 0x80,
+	SES_CTRL_NV_CACHE_RQST_IDENT_SHIFT	= 7,
+
+	SES_CTRL_NV_CACHE_RQST_FAIL_BYTE	= 0,
+	SES_CTRL_NV_CACHE_RQST_FAIL_MASK	= 0x40,
+	SES_CTRL_NV_CACHE_RQST_FAIL_SHIFT	= 6
+};
+
+#define GEN_SES_CTRL_NV_CACHE_ACCESSORS(LCASE, UCASE)		\
+    GEN_ACCESSORS(ses_ctrl_nv_cache, SES_CTRL_NV_CACHE,	LCASE, UCASE)
+GEN_SES_CTRL_NV_CACHE_ACCESSORS(rqst_ident, RQST_IDENT)
+GEN_SES_CTRL_NV_CACHE_ACCESSORS(rqst_fail,  RQST_FAIL)
+#undef GEN_SES_CTRL_NV_CACHE_ACCESSORS
+
+/*----------------- Invalid Operation Reason Control Element -----------------*/
+struct ses_ctrl_invalid_op_reason {
+	struct ses_ctrl_common common;
+	uint8_t bytes[3];
+};
+
+/* There are no element specific fields currently defined in the spec. */
+
+/*--------------- Uninterruptible Power Supply Control Element ---------------*/
+struct ses_ctrl_ups {
+	struct ses_ctrl_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_ctrl_ups_field_data {
+	SES_CTRL_UPS_RQST_IDENT_BYTE	= 2,
+	SES_CTRL_UPS_RQST_IDENT_MASK	= 0x80,
+	SES_CTRL_UPS_RQST_IDENT_SHIFT	= 7,
+
+	SES_CTRL_UPS_RQST_FAIL_BYTE	= 2,
+	SES_CTRL_UPS_RQST_FAIL_MASK	= 0x40,
+	SES_CTRL_UPS_RQST_FAIL_SHIFT	= 6
+};
+
+#define GEN_SES_CTRL_UPS_ACCESSORS(LCASE, UCASE)	\
+    GEN_ACCESSORS(ses_ctrl_ups, SES_CTRL_UPS, LCASE, UCASE)
+GEN_SES_CTRL_UPS_ACCESSORS(rqst_ident, RQST_IDENT)
+GEN_SES_CTRL_UPS_ACCESSORS(rqst_fail,  RQST_FAIL)
+#undef GEN_SES_CTRL_UPS_ACCESSORS
+
+/*-------------------------- Display Control Element -------------------------*/
+struct ses_ctrl_display {
+	struct ses_ctrl_common common;
+	uint8_t bytes[1];
+	uint8_t display_character[2];
+};
+
+enum ses_ctrl_display_field_data {
+	SES_CTRL_DISPLAY_RQST_IDENT_BYTE	= 0,
+	SES_CTRL_DISPLAY_RQST_IDENT_MASK	= 0x80,
+	SES_CTRL_DISPLAY_RQST_IDENT_SHIFT	= 7,
+
+	SES_CTRL_DISPLAY_RQST_FAIL_BYTE		= 0,
+	SES_CTRL_DISPLAY_RQST_FAIL_MASK		= 0x40,
+	SES_CTRL_DISPLAY_RQST_FAIL_SHIFT	= 6,
+
+	SES_CTRL_DISPLAY_DISPLAY_MODE_BYTE	= 0,
+	SES_CTRL_DISPLAY_DISPLAY_MODE_MASK	= 0x03,
+	SES_CTRL_DISPLAY_DISPLAY_MODE_SHIFT	= 6,
+	SES_CTRL_DISPLAY_DISPLAY_MODE_UNCHANGED = 0x0,
+	SES_CTRL_DISPLAY_DISPLAY_MODE_ESP	= 0x1,
+	SES_CTRL_DISPLAY_DISPLAY_MODE_DC_FIELD	= 0x2
+};
+
+#define GEN_SES_CTRL_DISPLAY_ACCESSORS(LCASE, UCASE)	\
+    GEN_ACCESSORS(ses_ctrl_display, SES_CTRL_DISPLAY, LCASE, UCASE)
+GEN_SES_CTRL_DISPLAY_ACCESSORS(rqst_ident,   RQST_IDENT)
+GEN_SES_CTRL_DISPLAY_ACCESSORS(rqst_fail,    RQST_FAIL)
+GEN_SES_CTRL_DISPLAY_ACCESSORS(display_mode, DISPLAY_MODE)
+#undef GEN_SES_CTRL_DISPLAY_ACCESSORS
+
+/*----------------------- Key Pad Entry Control Element ----------------------*/
+struct ses_ctrl_key_pad_entry {
+	struct ses_ctrl_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_ctrl_key_pad_entry_field_data {
+	SES_CTRL_KEY_PAD_ENTRY_RQST_IDENT_BYTE	= 0,
+	SES_CTRL_KEY_PAD_ENTRY_RQST_IDENT_MASK	= 0x80,
+	SES_CTRL_KEY_PAD_ENTRY_RQST_IDENT_SHIFT	= 7,
+
+	SES_CTRL_KEY_PAD_ENTRY_RQST_FAIL_BYTE	= 0,
+	SES_CTRL_KEY_PAD_ENTRY_RQST_FAIL_MASK	= 0x40,
+	SES_CTRL_KEY_PAD_ENTRY_RQST_FAIL_SHIFT	= 6
+};
+
+#define GEN_SES_CTRL_KEY_PAD_ENTRY_ACCESSORS(LCASE, UCASE)	\
+    GEN_ACCESSORS(ses_ctrl_key_pad_entry, SES_CTRL_KEY_PAD_ENTRY, LCASE, UCASE)
+GEN_SES_CTRL_KEY_PAD_ENTRY_ACCESSORS(rqst_ident,   RQST_IDENT)
+GEN_SES_CTRL_KEY_PAD_ENTRY_ACCESSORS(rqst_fail,    RQST_FAIL)
+#undef GEN_SES_CTRL_KEY_PAD_ENTRY_ACCESSORS
+
+/*------------------------- Enclosure Control Element ------------------------*/
+struct ses_ctrl_enclosure {
+	struct ses_ctrl_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_ctrl_enclosure_field_data {
+	SES_CTRL_ENCLOSURE_RQST_IDENT_BYTE		= 0,
+	SES_CTRL_ENCLOSURE_RQST_IDENT_MASK		= 0x80,
+	SES_CTRL_ENCLOSURE_RQST_IDENT_SHIFT		= 7,
+
+	SES_CTRL_ENCLOSURE_POWER_CYCLE_RQST_BYTE	= 1,
+	SES_CTRL_ENCLOSURE_POWER_CYCLE_RQST_MASK	= 0xC0,
+	SES_CTRL_ENCLOSURE_POWER_CYCLE_RQST_SHIFT	= 6,
+	SES_CTRL_ENCLOSURE_POWER_CYCLE_RQST_NONE	= 0x0,
+	SES_CTRL_ENCLOSURE_POWER_CYCLE_RQST_AFTER_DELAY	= 0x1,
+	SES_CTRL_ENCLOSURE_POWER_CYCLE_RQST_CANCEL	= 0x2,
+
+	SES_CTRL_ENCLOSURE_POWER_CYCLE_DELAY_BYTE	= 1,
+	SES_CTRL_ENCLOSURE_POWER_CYCLE_DELAY_MASK	= 0x3F,
+	SES_CTRL_ENCLOSURE_POWER_CYCLE_DELAY_SHIFT	= 0,
+	SES_CTRL_ENCLOSURE_POWER_CYCLE_DELAY_MAX	= 60,/*minutes*/
+
+	SES_CTRL_ENCLOSURE_POWER_OFF_DURATION_BYTE	= 2,
+	SES_CTRL_ENCLOSURE_POWER_OFF_DURATION_MASK	= 0xFC,
+	SES_CTRL_ENCLOSURE_POWER_OFF_DURATION_SHIFT	= 2,
+	SES_CTRL_ENCLOSURE_POWER_OFF_DURATION_MAX_AUTO	= 60,
+	SES_CTRL_ENCLOSURE_POWER_OFF_DURATION_MANUAL	= 63,
+
+	SES_CTRL_ENCLOSURE_RQST_FAIL_BYTE		= 2,
+	SES_CTRL_ENCLOSURE_RQST_FAIL_MASK		= 0x02,
+	SES_CTRL_ENCLOSURE_RQST_FAIL_SHIFT		= 1,
+
+	SES_CTRL_ENCLOSURE_RQST_WARN_BYTE		= 2,
+	SES_CTRL_ENCLOSURE_RQST_WARN_MASK		= 0x01,
+	SES_CTRL_ENCLOSURE_RQST_WARN_SHIFT		= 0
+};
+
+#define GEN_SES_CTRL_ENCLOSURE_ACCESSORS(LCASE, UCASE)		\
+    GEN_ACCESSORS(ses_ctrl_enclosure, SES_CTRL_ENCLOSURE, LCASE, UCASE)
+GEN_SES_CTRL_ENCLOSURE_ACCESSORS(rqst_ident,         RQST_IDENT)
+GEN_SES_CTRL_ENCLOSURE_ACCESSORS(power_cycle_rqst,   POWER_CYCLE_RQST)
+GEN_SES_CTRL_ENCLOSURE_ACCESSORS(power_cycle_delay,  POWER_CYCLE_DELAY)
+GEN_SES_CTRL_ENCLOSURE_ACCESSORS(power_off_duration, POWER_OFF_DURATION)
+GEN_SES_CTRL_ENCLOSURE_ACCESSORS(rqst_fail,          RQST_FAIL)
+GEN_SES_CTRL_ENCLOSURE_ACCESSORS(rqst_warn,          RQST_WARN)
+#undef GEN_SES_CTRL_ENCLOSURE_ACCESSORS
+
+/*------------------- SCSI Port/Transceiver Control Element ------------------*/
+struct ses_ctrl_scsi_port_or_xcvr {
+	struct ses_ctrl_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_ctrl_scsi_port_or_xcvr_field_data {
+	SES_CTRL_SCSI_PORT_OR_XCVR_RQST_IDENT_BYTE	= 0,
+	SES_CTRL_SCSI_PORT_OR_XCVR_RQST_IDENT_MASK	= 0x80,
+	SES_CTRL_SCSI_PORT_OR_XCVR_RQST_IDENT_SHIFT	= 7,
+
+	SES_CTRL_SCSI_PORT_OR_XCVR_RQST_FAIL_BYTE	= 0,
+	SES_CTRL_SCSI_PORT_OR_XCVR_RQST_FAIL_MASK	= 0x40,
+	SES_CTRL_SCSI_PORT_OR_XCVR_RQST_FAIL_SHIFT	= 6,
+
+	SES_CTRL_SCSI_PORT_OR_XCVR_DISABLE_BYTE		= 2,
+	SES_CTRL_SCSI_PORT_OR_XCVR_DISABLE_MASK		= 0x10,
+	SES_CTRL_SCSI_PORT_OR_XCVR_DISABLE_SHIFT	= 4
+};
+
+#define GEN_SES_CTRL_SCSI_PORT_OR_XCVR_ACCESSORS(LCASE, UCASE)		 \
+    GEN_ACCESSORS(ses_ctrl_scsi_port_or_xcvr, SES_CTRL_SCSI_PORT_OR_XCVR,\
+		  LCASE, UCASE)
+GEN_SES_CTRL_SCSI_PORT_OR_XCVR_ACCESSORS(rqst_ident, RQST_IDENT)
+GEN_SES_CTRL_SCSI_PORT_OR_XCVR_ACCESSORS(disable,    DISABLE)
+GEN_SES_CTRL_SCSI_PORT_OR_XCVR_ACCESSORS(rqst_fail,  RQST_FAIL)
+#undef GEN_SES_CTRL_SCSI_PORT_OR_XCVR_ACCESSORS
+
+/*------------------------- Language Control Element -------------------------*/
+struct ses_ctrl_language {
+	struct ses_ctrl_common common;
+	uint8_t bytes[1];
+	uint8_t language_code[2];
+};
+
+enum ses_ctrl_language_field_data {
+	SES_CTRL_LANGUAGE_RQST_IDENT_BYTE	= 0,
+	SES_CTRL_LANGUAGE_RQST_IDENT_MASK	= 0x80,
+	SES_CTRL_LANGUAGE_RQST_IDENT_SHIFT	= 7
+};
+
+#define GEN_SES_CTRL_LANGUAGE_ACCESSORS(LCASE, UCASE)		 \
+    GEN_ACCESSORS(ses_ctrl_language, SES_CTRL_LANGUAGE, LCASE, UCASE)
+GEN_SES_CTRL_LANGUAGE_ACCESSORS(rqst_ident, RQST_IDENT)
+#undef GEN_SES_CTRL_LANGUAGE_ACCESSORS
+
+/*-------------------- Communication Port Control Element --------------------*/
+struct ses_ctrl_comm_port {
+	struct ses_ctrl_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_ctrl_comm_port_field_data {
+	SES_CTRL_COMM_PORT_RQST_IDENT_BYTE	= 0,
+	SES_CTRL_COMM_PORT_RQST_IDENT_MASK	= 0x80,
+	SES_CTRL_COMM_PORT_RQST_IDENT_SHIFT	= 7,
+
+	SES_CTRL_COMM_PORT_RQST_FAIL_BYTE	= 0,
+	SES_CTRL_COMM_PORT_RQST_FAIL_MASK	= 0x40,
+	SES_CTRL_COMM_PORT_RQST_FAIL_SHIFT	= 6,
+
+	SES_CTRL_COMM_PORT_DISABLE_BYTE		= 2,
+	SES_CTRL_COMM_PORT_DISABLE_MASK		= 0x01,
+	SES_CTRL_COMM_PORT_DISABLE_SHIFT	= 0
+};
+
+#define GEN_SES_CTRL_COMM_PORT_ACCESSORS(LCASE, UCASE)		 \
+    GEN_ACCESSORS(ses_ctrl_comm_port, SES_CTRL_COMM_PORT, LCASE, UCASE)
+GEN_SES_CTRL_COMM_PORT_ACCESSORS(rqst_ident, RQST_IDENT)
+GEN_SES_CTRL_COMM_PORT_ACCESSORS(rqst_fail,  RQST_FAIL)
+GEN_SES_CTRL_COMM_PORT_ACCESSORS(disable,    DISABLE)
+#undef GEN_SES_CTRL_COMM_PORT_ACCESSORS
+
+/*---------------------- Voltage Sensor Control Element ----------------------*/
+struct ses_ctrl_voltage_sensor {
+	struct ses_ctrl_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_ctrl_voltage_sensor_field_data {
+	SES_CTRL_VOLTAGE_SENSOR_RQST_IDENT_BYTE		= 0,
+	SES_CTRL_VOLTAGE_SENSOR_RQST_IDENT_MASK		= 0x80,
+	SES_CTRL_VOLTAGE_SENSOR_RQST_IDENT_SHIFT	= 7,
+
+	SES_CTRL_VOLTAGE_SENSOR_RQST_FAIL_BYTE		= 0,
+	SES_CTRL_VOLTAGE_SENSOR_RQST_FAIL_MASK		= 0x40,
+	SES_CTRL_VOLTAGE_SENSOR_RQST_FAIL_SHIFT		= 6
+};
+
+#define GEN_SES_CTRL_VOLTAGE_SENSOR_ACCESSORS(LCASE, UCASE)		\
+    GEN_ACCESSORS(ses_ctrl_voltage_sensor, SES_CTRL_VOLTAGE_SENSOR,	\
+		  LCASE, UCASE)
+GEN_SES_CTRL_VOLTAGE_SENSOR_ACCESSORS(rqst_ident, RQST_IDENT)
+GEN_SES_CTRL_VOLTAGE_SENSOR_ACCESSORS(rqst_fail,  RQST_FAIL)
+#undef GEN_SES_CTRL_VOLTAGE_SENSOR_ACCESSORS
+
+/*---------------------- Current Sensor Control Element ----------------------*/
+struct ses_ctrl_current_sensor {
+	struct ses_ctrl_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_ctrl_current_sensor_field_data {
+	SES_CTRL_CURRENT_SENSOR_RQST_IDENT_BYTE		= 0,
+	SES_CTRL_CURRENT_SENSOR_RQST_IDENT_MASK		= 0x80,
+	SES_CTRL_CURRENT_SENSOR_RQST_IDENT_SHIFT	= 7,
+
+	SES_CTRL_CURRENT_SENSOR_RQST_FAIL_BYTE		= 0,
+	SES_CTRL_CURRENT_SENSOR_RQST_FAIL_MASK		= 0x40,
+	SES_CTRL_CURRENT_SENSOR_RQST_FAIL_SHIFT		= 6
+};
+
+#define GEN_SES_CTRL_CURRENT_SENSOR_ACCESSORS(LCASE, UCASE)		\
+    GEN_ACCESSORS(ses_ctrl_current_sensor, SES_CTRL_CURRENT_SENSOR,	\
+		  LCASE, UCASE)
+GEN_SES_CTRL_CURRENT_SENSOR_ACCESSORS(rqst_ident, RQST_IDENT)
+GEN_SES_CTRL_CURRENT_SENSOR_ACCESSORS(rqst_fail,  RQST_FAIL)
+#undef GEN_SES_CTRL_CURRENT_SENSOR_ACCESSORS
+
+/*--------------------- SCSI Target Port Control Element ---------------------*/
+struct ses_ctrl_target_port {
+	struct ses_ctrl_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_ctrl_scsi_target_port_field_data {
+	SES_CTRL_TARGET_PORT_RQST_IDENT_BYTE	= 0,
+	SES_CTRL_TARGET_PORT_RQST_IDENT_MASK	= 0x80,
+	SES_CTRL_TARGET_PORT_RQST_IDENT_SHIFT	= 7,
+
+	SES_CTRL_TARGET_PORT_RQST_FAIL_BYTE	= 0,
+	SES_CTRL_TARGET_PORT_RQST_FAIL_MASK	= 0x40,
+	SES_CTRL_TARGET_PORT_RQST_FAIL_SHIFT	= 6,
+
+	SES_CTRL_TARGET_PORT_ENABLE_BYTE	= 2,
+	SES_CTRL_TARGET_PORT_ENABLE_MASK	= 0x01,
+	SES_CTRL_TARGET_PORT_ENABLE_SHIFT	= 0
+};
+
+#define GEN_SES_CTRL_TARGET_PORT_ACCESSORS(LCASE, UCASE)	\
+    GEN_ACCESSORS(ses_ctrl_target_port, SES_CTRL_TARGET_PORT, LCASE, UCASE)
+GEN_SES_CTRL_TARGET_PORT_ACCESSORS(rqst_ident, RQST_IDENT)
+GEN_SES_CTRL_TARGET_PORT_ACCESSORS(rqst_fail,  RQST_FAIL)
+GEN_SES_CTRL_TARGET_PORT_ACCESSORS(enable,     ENABLE)
+#undef GEN_SES_CTRL_TARGET_PORT_ACCESSORS
+
+/*-------------------- SCSI Initiator Port Control Element -------------------*/
+struct ses_ctrl_initiator_port {
+	struct ses_ctrl_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_ctrl_initiator_port_field_data {
+	SES_CTRL_INITIATOR_PORT_RQST_IDENT_BYTE		= 0,
+	SES_CTRL_INITIATOR_PORT_RQST_IDENT_MASK		= 0x80,
+	SES_CTRL_INITIATOR_PORT_RQST_IDENT_SHIFT	= 7,
+
+	SES_CTRL_INITIATOR_PORT_RQST_FAIL_BYTE		= 0,
+	SES_CTRL_INITIATOR_PORT_RQST_FAIL_MASK		= 0x40,
+	SES_CTRL_INITIATOR_PORT_RQST_FAIL_SHIFT		= 6,
+
+	SES_CTRL_INITIATOR_PORT_ENABLE_BYTE		= 2,
+	SES_CTRL_INITIATOR_PORT_ENABLE_MASK		= 0x01,
+	SES_CTRL_INITIATOR_PORT_ENABLE_SHIFT		= 0
+};
+
+#define GEN_SES_CTRL_INITIATOR_PORT_ACCESSORS(LCASE, UCASE)		\
+    GEN_ACCESSORS(ses_ctrl_initiator_port, SES_CTRL_INITIATOR_PORT,	\
+		  LCASE, UCASE)
+GEN_SES_CTRL_INITIATOR_PORT_ACCESSORS(rqst_ident, RQST_IDENT)
+GEN_SES_CTRL_INITIATOR_PORT_ACCESSORS(rqst_fail,  RQST_FAIL)
+GEN_SES_CTRL_INITIATOR_PORT_ACCESSORS(enable,     ENABLE)
+#undef GEN_SES_CTRL_INITIATOR_PORT_ACCESSORS
+
+/*-------------------- Simple Subenclosure Control Element -------------------*/
+struct ses_ctrl_simple_subenc {
+	struct ses_ctrl_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_ctrl_simple_subenc_field_data {
+	SES_CTRL_SIMPlE_SUBSES_RQST_IDENT_BYTE	= 0,
+	SES_CTRL_SIMPlE_SUBSES_RQST_IDENT_MASK	= 0x80,
+	SES_CTRL_SIMPlE_SUBSES_RQST_IDENT_SHIFT	= 7,
+
+	SES_CTRL_SIMPlE_SUBSES_RQST_FAIL_BYTE	= 0,
+	SES_CTRL_SIMPlE_SUBSES_RQST_FAIL_MASK	= 0x40,
+	SES_CTRL_SIMPlE_SUBSES_RQST_FAIL_SHIFT	= 6
+};
+
+#define GEN_SES_CTRL_SIMPlE_SUBSES_ACCESSORS(LCASE, UCASE)		\
+    GEN_ACCESSORS(ses_ctrl_simple_subenc, SES_CTRL_SIMPlE_SUBSES,	\
+		  LCASE, UCASE)
+GEN_SES_CTRL_SIMPlE_SUBSES_ACCESSORS(rqst_ident, RQST_IDENT)
+GEN_SES_CTRL_SIMPlE_SUBSES_ACCESSORS(rqst_fail,  RQST_FAIL)
+#undef GEN_SES_CTRL_SIMPlE_SUBSES_ACCESSORS
+
+/*----------------------- SAS Expander Control Element -----------------------*/
+struct ses_ctrl_sas_expander {
+	struct ses_ctrl_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_ctrl_sas_expander_field_data {
+	SES_CTRL_SAS_EXPANDER_RQST_IDENT_BYTE	= 0,
+	SES_CTRL_SAS_EXPANDER_RQST_IDENT_MASK	= 0x80,
+	SES_CTRL_SAS_EXPANDER_RQST_IDENT_SHIFT	= 7,
+
+	SES_CTRL_SAS_EXPANDER_RQST_FAIL_BYTE	= 0,
+	SES_CTRL_SAS_EXPANDER_RQST_FAIL_MASK	= 0x40,
+	SES_CTRL_SAS_EXPANDER_RQST_FAIL_SHIFT	= 6
+};
+
+#define GEN_SES_CTRL_SAS_EXPANDER_ACCESSORS(LCASE, UCASE)	\
+    GEN_ACCESSORS(ses_ctrl_sas_expander, SES_CTRL_SAS_EXPANDER,	LCASE, UCASE)
+GEN_SES_CTRL_SAS_EXPANDER_ACCESSORS(rqst_ident, RQST_IDENT)
+GEN_SES_CTRL_SAS_EXPANDER_ACCESSORS(rqst_fail,  RQST_FAIL)
+#undef GEN_SES_CTRL_SAS_EXPANDER_ACCESSORS
+
+/*----------------------- SAS Connector Control Element ----------------------*/
+struct ses_ctrl_sas_connector {
+	struct ses_ctrl_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_ctrl_sas_connector_field_data {
+	SES_CTRL_SAS_CONNECTOR_RQST_IDENT_BYTE		= 0,
+	SES_CTRL_SAS_CONNECTOR_RQST_IDENT_MASK		= 0x80,
+	SES_CTRL_SAS_CONNECTOR_RQST_IDENT_SHIFT		= 7,
+
+	SES_CTRL_SAS_CONNECTOR_RQST_FAIL_BYTE		= 2,
+	SES_CTRL_SAS_CONNECTOR_RQST_FAIL_MASK		= 0x40,
+	SES_CTRL_SAS_CONNECTOR_RQST_FAIL_SHIFT		= 6
+};
+
+#define GEN_SES_CTRL_SAS_CONNECTOR_ACCESSORS(LCASE, UCASE)		\
+    GEN_ACCESSORS(ses_ctrl_sas_connector, SES_CTRL_SAS_CONNECTOR,	\
+		  LCASE, UCASE)
+GEN_SES_CTRL_SAS_CONNECTOR_ACCESSORS(rqst_ident, RQST_IDENT)
+GEN_SES_CTRL_SAS_CONNECTOR_ACCESSORS(rqst_fail,  RQST_FAIL)
+#undef GEN_SES_CTRL_SAS_CONNECTOR_ACCESSORS
+
+/*------------------------- Universal Control Element ------------------------*/
+union ses_ctrl_element {
+	struct ses_ctrl_common            common;
+	struct ses_ctrl_dev_slot          dev_slot;
+	struct ses_ctrl_array_dev_slot    array_dev_slot;
+	struct ses_ctrl_power_supply      power_supply;
+	struct ses_ctrl_cooling           cooling;
+	struct ses_ctrl_temp_sensor       temp_sensor;
+	struct ses_ctrl_door_lock         door_lock;
+	struct ses_ctrl_audible_alarm     audible_alarm;
+	struct ses_ctrl_ecc_electronics   ecc_electronics;
+	struct ses_ctrl_scc_electronics   scc_electronics;
+	struct ses_ctrl_nv_cache          nv_cache;
+	struct ses_ctrl_invalid_op_reason invalid_op_reason;
+	struct ses_ctrl_ups               ups;
+	struct ses_ctrl_display           display;
+	struct ses_ctrl_key_pad_entry     key_pad_entry;
+	struct ses_ctrl_scsi_port_or_xcvr scsi_port_or_xcvr;
+	struct ses_ctrl_language          language;
+	struct ses_ctrl_comm_port         comm_port;
+	struct ses_ctrl_voltage_sensor    voltage_sensor;
+	struct ses_ctrl_current_sensor    current_sensor;
+	struct ses_ctrl_target_port	  target_port;
+	struct ses_ctrl_initiator_port    initiator_port;
+	struct ses_ctrl_simple_subenc	  simple_subenc;
+	struct ses_ctrl_sas_expander      sas_expander;
+	struct ses_ctrl_sas_connector     sas_connector;
+};
+
+/*--------------------- SCSI SES Control Diagnostic Page ---------------------*/
+struct ses_ctrl_page {
+	struct ses_page_hdr hdr;
+	union ses_ctrl_element   elements[];
+};
+
+enum ses_ctrl_page_field_data {
+	SES_CTRL_PAGE_INFO_MASK		= 0x08,
+	SES_CTRL_PAGE_INFO_SHIFT	= 3,
+
+	SES_CTRL_PAGE_NON_CRIT_MASK	= 0x04,
+	SES_CTRL_PAGE_NON_CRIT_SHIFT	= 2,
+
+	SES_CTRL_PAGE_CRIT_MASK		= 0x02,
+	SES_CTRL_PAGE_CRIT_SHIFT	= 1,
+
+	SES_CTRL_PAGE_UNRECOV_MASK	= 0x01,
+	SES_CTRL_PAGE_UNRECOV_SHIFT	= 0
+};
+
+#define GEN_SES_CTRL_PAGE_ACCESSORS(LCASE, UCASE) \
+    GEN_HDR_ACCESSORS(ses_ctrl_page, SES_CTRL_PAGE, LCASE, UCASE)
+
+GEN_SES_CTRL_PAGE_ACCESSORS(info,     INFO)
+GEN_SES_CTRL_PAGE_ACCESSORS(non_crit, NON_CRIT)
+GEN_SES_CTRL_PAGE_ACCESSORS(crit,     CRIT)
+GEN_SES_CTRL_PAGE_ACCESSORS(unrecov,  UNRECOV)
+#undef GEN_SES_CTRL_PAGE_ACCESSORS
+
+/*================= SCSI SES Status Diagnostic Page Structures ===============*/
+struct ses_status_common {
+	uint8_t bytes[1];
+};
+
+enum ses_status_common_field_data {
+	SES_STATUS_COMMON_PRDFAIL_BYTE			= 0,
+	SES_STATUS_COMMON_PRDFAIL_MASK			= 0x40,
+	SES_STATUS_COMMON_PRDFAIL_SHIFT			= 6,
+
+	SES_STATUS_COMMON_DISABLED_BYTE			= 0,
+	SES_STATUS_COMMON_DISABLED_MASK			= 0x20,
+	SES_STATUS_COMMON_DISABLED_SHIFT		= 5,
+
+	SES_STATUS_COMMON_SWAP_BYTE			= 0,
+	SES_STATUS_COMMON_SWAP_MASK			= 0x10,
+	SES_STATUS_COMMON_SWAP_SHIFT			= 4,
+
+	SES_STATUS_COMMON_ELEMENT_STATUS_CODE_BYTE	= 0,
+	SES_STATUS_COMMON_ELEMENT_STATUS_CODE_MASK	= 0x0F,
+	SES_STATUS_COMMON_ELEMENT_STATUS_CODE_SHIFT	= 0
+};
+
+#define GEN_SES_STATUS_COMMON_ACCESSORS(LCASE, UCASE) \
+    GEN_GETTER(ses_status_common, SES_STATUS_COMMON, LCASE, UCASE)
+
+GEN_SES_STATUS_COMMON_ACCESSORS(prdfail,             PRDFAIL)
+GEN_SES_STATUS_COMMON_ACCESSORS(disabled,            DISABLED)
+GEN_SES_STATUS_COMMON_ACCESSORS(swap,                SWAP)
+GEN_SES_STATUS_COMMON_ACCESSORS(element_status_code, ELEMENT_STATUS_CODE)
+#undef GEN_SES_STATUS_COMMON_ACCESSORS
+
+/*------------------------- Device Slot Status Element -----------------------*/
+struct ses_status_dev_slot {
+	struct ses_status_common common;
+	uint8_t slot_address;
+	uint8_t bytes[2];
+};
+
+enum ses_status_dev_slot_field_data {
+	SES_STATUS_DEV_SLOT_APP_CLIENT_BYPED_A_BYTE	= 0,
+	SES_STATUS_DEV_SLOT_APP_CLIENT_BYPED_A_MASK	= 0x80,
+	SES_STATUS_DEV_SLOT_APP_CLIENT_BYPED_A_SHIFT	= 7,
+
+	SES_STATUS_DEV_SLOT_DO_NOT_REMOVE_BYTE		= 0,
+	SES_STATUS_DEV_SLOT_DO_NOT_REMOVE_MASK		= 0x40,
+	SES_STATUS_DEV_SLOT_DO_NOT_REMOVE_SHIFT		= 6,
+
+	SES_STATUS_DEV_SLOT_ENCLOSURE_BYPED_A_BYTE	= 0,
+	SES_STATUS_DEV_SLOT_ENCLOSURE_BYPED_A_MASK	= 0x20,
+	SES_STATUS_DEV_SLOT_ENCLOSURE_BYPED_A_SHIFT	= 5,
+
+	SES_STATUS_DEV_SLOT_ENCLOSURE_BYPED_B_BYTE	= 0,
+	SES_STATUS_DEV_SLOT_ENCLOSURE_BYPED_B_MASK	= 0x10,
+	SES_STATUS_DEV_SLOT_ENCLOSURE_BYPED_B_SHIFT	= 4,
+
+	SES_STATUS_DEV_SLOT_INSERT_READY_BYTE		= 0,
+	SES_STATUS_DEV_SLOT_INSERT_READY_MASK		= 0x08,
+	SES_STATUS_DEV_SLOT_INSERT_READY_SHIFT		= 3,
+
+	SES_STATUS_DEV_SLOT_REMOVE_BYTE			= 0,
+	SES_STATUS_DEV_SLOT_REMOVE_MASK			= 0x04,
+	SES_STATUS_DEV_SLOT_REMOVE_SHIFT		= 2,
+
+	SES_STATUS_DEV_SLOT_IDENT_BYTE			= 0,
+	SES_STATUS_DEV_SLOT_IDENT_MASK			= 0x02,
+	SES_STATUS_DEV_SLOT_IDENT_SHIFT			= 1,
+
+	SES_STATUS_DEV_SLOT_REPORT_BYTE			= 0,
+	SES_STATUS_DEV_SLOT_REPORT_MASK			= 0x01,
+	SES_STATUS_DEV_SLOT_REPORT_SHIFT		= 0,
+
+	SES_STATUS_DEV_SLOT_APP_CLIENT_BYPED_B_BYTE	= 1,
+	SES_STATUS_DEV_SLOT_APP_CLIENT_BYPED_B_MASK	= 0x80,
+	SES_STATUS_DEV_SLOT_APP_CLIENT_BYPED_B_SHIFT	= 7,
+
+	SES_STATUS_DEV_SLOT_FAULT_SENSED_BYTE		= 1,
+	SES_STATUS_DEV_SLOT_FAULT_SENSED_MASK		= 0x40,
+	SES_STATUS_DEV_SLOT_FAULT_SENSED_SHIFT		= 6,
+
+	SES_STATUS_DEV_SLOT_FAULT_REQUESTED_BYTE	= 1,
+	SES_STATUS_DEV_SLOT_FAULT_REQUESTED_MASK	= 0x20,
+	SES_STATUS_DEV_SLOT_FAULT_REQUESTED_SHIFT	= 5,
+
+	SES_STATUS_DEV_SLOT_DEVICE_OFF_BYTE		= 1,
+	SES_STATUS_DEV_SLOT_DEVICE_OFF_MASK		= 0x10,
+	SES_STATUS_DEV_SLOT_DEVICE_OFF_SHIFT		= 4,
+
+	SES_STATUS_DEV_SLOT_BYPED_A_BYTE		= 1,
+	SES_STATUS_DEV_SLOT_BYPED_A_MASK		= 0x08,
+	SES_STATUS_DEV_SLOT_BYPED_A_SHIFT		= 3,
+
+	SES_STATUS_DEV_SLOT_BYPED_B_BYTE		= 1,
+	SES_STATUS_DEV_SLOT_BYPED_B_MASK		= 0x04,
+	SES_STATUS_DEV_SLOT_BYPED_B_SHIFT		= 2,
+
+	SES_STATUS_DEV_SLOT_DEVICE_BYPED_A_BYTE		= 1,
+	SES_STATUS_DEV_SLOT_DEVICE_BYPED_A_MASK		= 0x02,
+	SES_STATUS_DEV_SLOT_DEVICE_BYPED_A_SHIFT	= 1,
+
+	SES_STATUS_DEV_SLOT_DEVICE_BYPED_B_BYTE		= 1,
+	SES_STATUS_DEV_SLOT_DEVICE_BYPED_B_MASK		= 0x01,
+	SES_STATUS_DEV_SLOT_DEVICE_BYPED_B_SHIFT	= 0
+};
+#define GEN_SES_STATUS_DEV_SLOT_ACCESSORS(LCASE, UCASE) \
+    GEN_GETTER(ses_status_dev_slot, SES_STATUS_DEV_SLOT, LCASE, UCASE)
+
+GEN_SES_STATUS_DEV_SLOT_ACCESSORS(app_client_byped_a, APP_CLIENT_BYPED_A)
+GEN_SES_STATUS_DEV_SLOT_ACCESSORS(do_not_remove,      DO_NOT_REMOVE)
+GEN_SES_STATUS_DEV_SLOT_ACCESSORS(enclosure_byped_a,  ENCLOSURE_BYPED_A)
+GEN_SES_STATUS_DEV_SLOT_ACCESSORS(enclosure_byped_b,  ENCLOSURE_BYPED_B)
+GEN_SES_STATUS_DEV_SLOT_ACCESSORS(insert_ready,       INSERT_READY)
+GEN_SES_STATUS_DEV_SLOT_ACCESSORS(remove,             REMOVE)
+GEN_SES_STATUS_DEV_SLOT_ACCESSORS(ident,              IDENT)
+GEN_SES_STATUS_DEV_SLOT_ACCESSORS(report,             REPORT)
+GEN_SES_STATUS_DEV_SLOT_ACCESSORS(app_client_byped_b, APP_CLIENT_BYPED_B)
+GEN_SES_STATUS_DEV_SLOT_ACCESSORS(fault_sensed,       FAULT_SENSED)
+GEN_SES_STATUS_DEV_SLOT_ACCESSORS(fault_requested,    FAULT_REQUESTED)
+GEN_SES_STATUS_DEV_SLOT_ACCESSORS(device_off,         DEVICE_OFF)
+GEN_SES_STATUS_DEV_SLOT_ACCESSORS(byped_a,            BYPED_A)
+GEN_SES_STATUS_DEV_SLOT_ACCESSORS(byped_b,            BYPED_B)
+GEN_SES_STATUS_DEV_SLOT_ACCESSORS(device_byped_a,     DEVICE_BYPED_A)
+GEN_SES_STATUS_DEV_SLOT_ACCESSORS(device_byped_b,     DEVICE_BYPED_B)
+#undef GEN_SES_STATUS_DEV_SLOT_ACCESSORS
+
+/*---------------------- Array Device Slot Status Element --------------------*/
+struct ses_status_array_dev_slot {
+	struct ses_status_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_status_array_dev_slot_field_data {
+	SES_STATUS_ARRAY_DEV_SLOT_OK_BYTE			= 0,
+	SES_STATUS_ARRAY_DEV_SLOT_OK_MASK			= 0x80,
+	SES_STATUS_ARRAY_DEV_SLOT_OK_SHIFT			= 7,
+
+	SES_STATUS_ARRAY_DEV_SLOT_RSVD_DEVICE_BYTE		= 0,
+	SES_STATUS_ARRAY_DEV_SLOT_RSVD_DEVICE_MASK		= 0x40,
+	SES_STATUS_ARRAY_DEV_SLOT_RSVD_DEVICE_SHIFT		= 6,
+
+	SES_STATUS_ARRAY_DEV_SLOT_HOT_SPARE_BYTE		= 0,
+	SES_STATUS_ARRAY_DEV_SLOT_HOT_SPARE_MASK		= 0x20,
+	SES_STATUS_ARRAY_DEV_SLOT_HOT_SPARE_SHIFT		= 5,
+
+	SES_STATUS_ARRAY_DEV_SLOT_CONS_CHECK_BYTE		= 0,
+	SES_STATUS_ARRAY_DEV_SLOT_CONS_CHECK_MASK		= 0x10,
+	SES_STATUS_ARRAY_DEV_SLOT_CONS_CHECK_SHIFT		= 4,
+
+	SES_STATUS_ARRAY_DEV_SLOT_IN_CRIT_ARRAY_BYTE		= 0,
+	SES_STATUS_ARRAY_DEV_SLOT_IN_CRIT_ARRAY_MASK		= 0x08,
+	SES_STATUS_ARRAY_DEV_SLOT_IN_CRIT_ARRAY_SHIFT		= 3,
+
+	SES_STATUS_ARRAY_DEV_SLOT_IN_FAILED_ARRAY_BYTE		= 0,
+	SES_STATUS_ARRAY_DEV_SLOT_IN_FAILED_ARRAY_MASK		= 0x04,
+	SES_STATUS_ARRAY_DEV_SLOT_IN_FAILED_ARRAY_SHIFT		= 2,
+
+	SES_STATUS_ARRAY_DEV_SLOT_REBUILD_REMAP_BYTE		= 0,
+	SES_STATUS_ARRAY_DEV_SLOT_REBUILD_REMAP_MASK		= 0x02,
+	SES_STATUS_ARRAY_DEV_SLOT_REBUILD_REMAP_SHIFT		= 1,
+
+	SES_STATUS_ARRAY_DEV_SLOT_REBUILD_REMAP_ABORT_BYTE	= 0,
+	SES_STATUS_ARRAY_DEV_SLOT_REBUILD_REMAP_ABORT_MASK	= 0x01,
+	SES_STATUS_ARRAY_DEV_SLOT_REBUILD_REMAP_ABORT_SHIFT	= 0
+
+	/*
+	 * The remaining fields are identical to the device
+	 * slot element type.  Access them through the device slot
+	 * element type and its accessors.
+	 */
+};
+#define GEN_SES_STATUS_ARRAY_DEV_SLOT_ACCESSORS(LCASE, UCASE)		\
+    GEN_GETTER(ses_status_array_dev_slot, SES_STATUS_ARRAY_DEV_SLOT,	\
+	       LCASE, UCASE)
+GEN_SES_STATUS_ARRAY_DEV_SLOT_ACCESSORS(ok,              OK)
+GEN_SES_STATUS_ARRAY_DEV_SLOT_ACCESSORS(rsvd_device,     RSVD_DEVICE)
+GEN_SES_STATUS_ARRAY_DEV_SLOT_ACCESSORS(hot_spare,       HOT_SPARE)
+GEN_SES_STATUS_ARRAY_DEV_SLOT_ACCESSORS(cons_check,      CONS_CHECK)
+GEN_SES_STATUS_ARRAY_DEV_SLOT_ACCESSORS(in_crit_array,   IN_CRIT_ARRAY)
+GEN_SES_STATUS_ARRAY_DEV_SLOT_ACCESSORS(in_failed_array, IN_FAILED_ARRAY)
+GEN_SES_STATUS_ARRAY_DEV_SLOT_ACCESSORS(rebuild_remap,   REBUILD_REMAP)
+GEN_SES_STATUS_ARRAY_DEV_SLOT_ACCESSORS(rebuild_remap_abort,
+					REBUILD_REMAP_ABORT)
+#undef GEN_SES_STATUS_ARRAY_DEV_SLOT_ACCESSORS
+
+/*----------------------- Power Supply Status Element ------------------------*/
+struct ses_status_power_supply {
+	struct ses_status_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_status_power_supply_field_data {
+	SES_STATUS_POWER_SUPPLY_IDENT_BYTE		= 0,
+	SES_STATUS_POWER_SUPPLY_IDENT_MASK		= 0x80,
+	SES_STATUS_POWER_SUPPLY_IDENT_SHIFT		= 7,
+
+	SES_STATUS_POWER_SUPPLY_DC_OVER_VOLTAGE_BYTE	= 1,
+	SES_STATUS_POWER_SUPPLY_DC_OVER_VOLTAGE_MASK	= 0x08,
+	SES_STATUS_POWER_SUPPLY_DC_OVER_VOLTAGE_SHIFT	= 3,
+
+	SES_STATUS_POWER_SUPPLY_DC_UNDER_VOLTAGE_BYTE	= 1,
+	SES_STATUS_POWER_SUPPLY_DC_UNDER_VOLTAGE_MASK	= 0x04,
+	SES_STATUS_POWER_SUPPLY_DC_UNDER_VOLTAGE_SHIFT	= 2,
+
+	SES_STATUS_POWER_SUPPLY_DC_OVER_CURRENT_BYTE	= 1,
+	SES_STATUS_POWER_SUPPLY_DC_OVER_CURRENT_MASK	= 0x02,
+	SES_STATUS_POWER_SUPPLY_DC_OVER_CURRENT_SHIFT	= 1,
+
+	SES_STATUS_POWER_SUPPLY_HOT_SWAP_BYTE		= 2,
+	SES_STATUS_POWER_SUPPLY_HOT_SWAP_MASK		= 0x80,
+	SES_STATUS_POWER_SUPPLY_HOT_SWAP_SHIFT		= 7,
+
+	SES_STATUS_POWER_SUPPLY_FAIL_BYTE		= 2,
+	SES_STATUS_POWER_SUPPLY_FAIL_MASK		= 0x40,
+	SES_STATUS_POWER_SUPPLY_FAIL_SHIFT		= 6,
+
+	SES_STATUS_POWER_SUPPLY_REQUESTED_ON_BYTE	= 2,
+	SES_STATUS_POWER_SUPPLY_REQUESTED_ON_MASK	= 0x20,
+	SES_STATUS_POWER_SUPPLY_REQUESTED_ON_SHIFT	= 5,
+
+	SES_STATUS_POWER_SUPPLY_OFF_BYTE		= 2,
+	SES_STATUS_POWER_SUPPLY_OFF_MASK		= 0x10,
+	SES_STATUS_POWER_SUPPLY_OFF_SHIFT		= 4,
+
+	SES_STATUS_POWER_SUPPLY_OVERTMP_FAIL_BYTE	= 2,
+	SES_STATUS_POWER_SUPPLY_OVERTMP_FAIL_MASK	= 0x08,
+	SES_STATUS_POWER_SUPPLY_OVERTMP_FAIL_SHIFT	= 3,
+
+	SES_STATUS_POWER_SUPPLY_TEMP_WARN_BYTE		= 2,
+	SES_STATUS_POWER_SUPPLY_TEMP_WARN_MASK		= 0x04,
+	SES_STATUS_POWER_SUPPLY_TEMP_WARN_SHIFT		= 2,
+
+	SES_STATUS_POWER_SUPPLY_AC_FAIL_BYTE		= 2,
+	SES_STATUS_POWER_SUPPLY_AC_FAIL_MASK		= 0x02,
+	SES_STATUS_POWER_SUPPLY_AC_FAIL_SHIFT		= 1,
+
+	SES_STATUS_POWER_SUPPLY_DC_FAIL_BYTE		= 2,
+	SES_STATUS_POWER_SUPPLY_DC_FAIL_MASK		= 0x01,
+	SES_STATUS_POWER_SUPPLY_DC_FAIL_SHIFT		= 0
+};
+
+#define GEN_SES_STATUS_POWER_SUPPLY_ACCESSORS(LCASE, UCASE)	\
+    GEN_GETTER(ses_status_power_supply, SES_STATUS_POWER_SUPPLY, LCASE, UCASE)
+GEN_SES_STATUS_POWER_SUPPLY_ACCESSORS(ident,            IDENT)
+GEN_SES_STATUS_POWER_SUPPLY_ACCESSORS(dc_over_voltage,  DC_OVER_VOLTAGE)
+GEN_SES_STATUS_POWER_SUPPLY_ACCESSORS(dc_under_voltage, DC_UNDER_VOLTAGE)
+GEN_SES_STATUS_POWER_SUPPLY_ACCESSORS(dc_over_current,  DC_OVER_CURRENT)
+GEN_SES_STATUS_POWER_SUPPLY_ACCESSORS(hot_swap,         HOT_SWAP)
+GEN_SES_STATUS_POWER_SUPPLY_ACCESSORS(fail,             FAIL)
+GEN_SES_STATUS_POWER_SUPPLY_ACCESSORS(requested_on,     REQUESTED_ON)
+GEN_SES_STATUS_POWER_SUPPLY_ACCESSORS(off,              OFF)
+GEN_SES_STATUS_POWER_SUPPLY_ACCESSORS(overtmp_fail,     OVERTMP_FAIL)
+GEN_SES_STATUS_POWER_SUPPLY_ACCESSORS(temp_warn,        TEMP_WARN)
+GEN_SES_STATUS_POWER_SUPPLY_ACCESSORS(ac_fail,          AC_FAIL)
+GEN_SES_STATUS_POWER_SUPPLY_ACCESSORS(dc_fail,          DC_FAIL)
+#undef GEN_SES_STATUS_POWER_SUPPLY_ACCESSORS
+
+/*-------------------------- Cooling Status Element --------------------------*/
+struct ses_status_cooling {
+	struct ses_status_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_status_cooling_field_data {
+	SES_STATUS_COOLING_IDENT_BYTE			= 0,
+	SES_STATUS_COOLING_IDENT_MASK			= 0x80,
+	SES_STATUS_COOLING_IDENT_SHIFT			= 7,
+
+	SES_STATUS_COOLING_ACTUAL_FAN_SPEED_MSB_BYTE	= 0,
+	SES_STATUS_COOLING_ACTUAL_FAN_SPEED_MSB_MASK	= 0x07,
+	SES_STATUS_COOLING_ACTUAL_FAN_SPEED_MSB_SHIFT	= 0,
+
+	SES_STATUS_COOLING_ACTUAL_FAN_SPEED_LSB_BYTE	= 1,
+	SES_STATUS_COOLING_ACTUAL_FAN_SPEED_LSB_MASK	= 0xFF,
+	SES_STATUS_COOLING_ACTUAL_FAN_SPEED_LSB_SHIFT	= 0,
+
+	SES_STATUS_COOLING_HOT_SWAP_BYTE		= 2,
+	SES_STATUS_COOLING_HOT_SWAP_MASK		= 0x40,
+	SES_STATUS_COOLING_HOT_SWAP_SHIFT		= 6,
+
+	SES_STATUS_COOLING_FAIL_BYTE			= 2,
+	SES_STATUS_COOLING_FAIL_MASK			= 0x40,
+	SES_STATUS_COOLING_FAIL_SHIFT			= 6,
+
+	SES_STATUS_COOLING_REQUESTED_ON_BYTE		= 2,
+	SES_STATUS_COOLING_REQUESTED_ON_MASK		= 0x20,
+	SES_STATUS_COOLING_REQUESTED_ON_SHIFT		= 5,
+
+	SES_STATUS_COOLING_OFF_BYTE			= 2,
+	SES_STATUS_COOLING_OFF_MASK			= 0x20,
+	SES_STATUS_COOLING_OFF_SHIFT			= 5,
+
+	SES_STATUS_COOLING_ACTUAL_SPEED_CODE_BYTE	= 2,
+	SES_STATUS_COOLING_ACTUAL_SPEED_CODE_MASK	= 0x07,
+	SES_STATUS_COOLING_ACTUAL_SPEED_CODE_SHIFT	= 2,
+	SES_STATUS_COOLING_ACTUAL_SPEED_CODE_STOPPED	= 0x00,
+	SES_STATUS_COOLING_ACTUAL_SPEED_CODE_LOWEST	= 0x01,
+	SES_STATUS_COOLING_ACTUAL_SPEED_CODE_HIGHEST	= 0x07
+};
+
+#define GEN_SES_STATUS_COOLING_ACCESSORS(LCASE, UCASE)	\
+    GEN_GETTER(ses_status_cooling, SES_STATUS_COOLING, LCASE, UCASE)
+GEN_SES_STATUS_COOLING_ACCESSORS(ident,                IDENT)
+GEN_SES_STATUS_COOLING_ACCESSORS(actual_fan_speed_msb, ACTUAL_FAN_SPEED_MSB)
+GEN_SES_STATUS_COOLING_ACCESSORS(actual_fan_speed_lsb, ACTUAL_FAN_SPEED_LSB)
+GEN_SES_STATUS_COOLING_ACCESSORS(hot_swap,             HOT_SWAP)
+GEN_SES_STATUS_COOLING_ACCESSORS(fail,                 FAIL)
+GEN_SES_STATUS_COOLING_ACCESSORS(requested_on,         REQUESTED_ON)
+GEN_SES_STATUS_COOLING_ACCESSORS(off,                  OFF)
+GEN_SES_STATUS_COOLING_ACCESSORS(actual_speed_code,    ACTUAL_SPEED_CODE)
+#undef GEN_SES_STATUS_COOLING_ACCESSORS
+
+static inline int
+ses_status_cooling_get_actual_fan_speed(struct ses_status_cooling *elem)
+{
+	return (ses_status_cooling_get_actual_fan_speed_msb(elem) << 8
+	      | ses_status_cooling_get_actual_fan_speed_lsb(elem));
+}
+
+/*-------------------- Temperature Sensor Status Element ---------------------*/
+struct ses_status_temp_sensor {
+	struct ses_status_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_status_temp_sensor_field_data {
+	SES_STATUS_TEMP_SENSOR_IDENT_BYTE		= 0,
+	SES_STATUS_TEMP_SENSOR_IDENT_MASK		= 0x80,
+	SES_STATUS_TEMP_SENSOR_IDENT_SHIFT		= 7,
+
+	SES_STATUS_TEMP_SENSOR_FAIL_BYTE		= 0,
+	SES_STATUS_TEMP_SENSOR_FAIL_MASK		= 0x40,
+	SES_STATUS_TEMP_SENSOR_FAIL_SHIFT		= 6,
+
+	SES_STATUS_TEMP_SENSOR_TEMPERATURE_BYTE		= 1,
+	SES_STATUS_TEMP_SENSOR_TEMPERATURE_MASK		= 0xFF,
+	SES_STATUS_TEMP_SENSOR_TEMPERATURE_SHIFT	= 0,
+
+	SES_STATUS_TEMP_SENSOR_OT_FAILURE_BYTE		= 2,
+	SES_STATUS_TEMP_SENSOR_OT_FAILURE_MASK		= 0x08,
+	SES_STATUS_TEMP_SENSOR_OT_FAILURE_SHIFT		= 3,
+
+	SES_STATUS_TEMP_SENSOR_OT_WARNING_BYTE		= 2,
+	SES_STATUS_TEMP_SENSOR_OT_WARNING_MASK		= 0x04,
+	SES_STATUS_TEMP_SENSOR_OT_WARNING_SHIFT		= 2,
+
+	SES_STATUS_TEMP_SENSOR_UT_FAILURE_BYTE		= 2,
+	SES_STATUS_TEMP_SENSOR_UT_FAILURE_MASK		= 0x02,
+	SES_STATUS_TEMP_SENSOR_UT_FAILURE_SHIFT		= 1,
+
+	SES_STATUS_TEMP_SENSOR_UT_WARNING_BYTE		= 2,
+	SES_STATUS_TEMP_SENSOR_UT_WARNING_MASK		= 0x01,
+	SES_STATUS_TEMP_SENSOR_UT_WARNING_SHIFT		= 0
+};
+
+#define GEN_SES_STATUS_TEMP_SENSOR_ACCESSORS(LCASE, UCASE)	\
+    GEN_GETTER(ses_status_temp_sensor, SES_STATUS_TEMP_SENSOR, LCASE, UCASE)
+GEN_SES_STATUS_TEMP_SENSOR_ACCESSORS(ident,       IDENT)
+GEN_SES_STATUS_TEMP_SENSOR_ACCESSORS(fail,        FAIL)
+GEN_SES_STATUS_TEMP_SENSOR_ACCESSORS(temperature, TEMPERATURE)
+GEN_SES_STATUS_TEMP_SENSOR_ACCESSORS(ot_failure,  OT_FAILURE)
+GEN_SES_STATUS_TEMP_SENSOR_ACCESSORS(ot_warning,  OT_WARNING)
+GEN_SES_STATUS_TEMP_SENSOR_ACCESSORS(ut_failure,  UT_FAILURE)
+GEN_SES_STATUS_TEMP_SENSOR_ACCESSORS(ut_warning,  UT_WARNING)
+#undef GEN_SES_STATUS_TEMP_SENSOR_ACCESSORS
+
+/*------------------------- Door Lock Status Element -------------------------*/
+struct ses_status_door_lock {
+	struct ses_status_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_status_door_lock_field_data {
+	SES_STATUS_DOOR_LOCK_IDENT_BYTE		= 0,
+	SES_STATUS_DOOR_LOCK_IDENT_MASK		= 0x80,
+	SES_STATUS_DOOR_LOCK_IDENT_SHIFT	= 7,
+
+	SES_STATUS_DOOR_LOCK_FAIL_BYTE		= 0,
+	SES_STATUS_DOOR_LOCK_FAIL_MASK		= 0x40,
+	SES_STATUS_DOOR_LOCK_FAIL_SHIFT		= 6,
+
+	SES_STATUS_DOOR_LOCK_UNLOCKED_BYTE	= 2,
+	SES_STATUS_DOOR_LOCK_UNLOCKED_MASK	= 0x01,
+	SES_STATUS_DOOR_LOCK_UNLOCKED_SHIFT	= 0
+};
+
+#define GEN_SES_STATUS_DOOR_LOCK_ACCESSORS(LCASE, UCASE)	\
+    GEN_GETTER(ses_status_door_lock, SES_STATUS_DOOR_LOCK, LCASE, UCASE)
+GEN_SES_STATUS_DOOR_LOCK_ACCESSORS(ident,    IDENT)
+GEN_SES_STATUS_DOOR_LOCK_ACCESSORS(fail,     FAIL)
+GEN_SES_STATUS_DOOR_LOCK_ACCESSORS(unlocked, UNLOCKED)
+#undef GEN_SES_STATUS_DOOR_LOCK_ACCESSORS
+
+/*----------------------- Audible Alarm Status Element -----------------------*/
+struct ses_status_audible_alarm {
+	struct ses_status_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_status_audible_alarm_field_data {
+	SES_STATUS_AUDIBLE_ALARM_IDENT_BYTE			= 0,
+	SES_STATUS_AUDIBLE_ALARM_IDENT_MASK			= 0x80,
+	SES_STATUS_AUDIBLE_ALARM_IDENT_SHIFT			= 7,
+
+	SES_STATUS_AUDIBLE_ALARM_FAIL_BYTE			= 0,
+	SES_STATUS_AUDIBLE_ALARM_FAIL_MASK			= 0x40,
+	SES_STATUS_AUDIBLE_ALARM_FAIL_SHIFT			= 6,
+
+	SES_STATUS_AUDIBLE_ALARM_RQST_MUTE_BYTE			= 2,
+	SES_STATUS_AUDIBLE_ALARM_RQST_MUTE_MASK			= 0x80,
+	SES_STATUS_AUDIBLE_ALARM_RQST_MUTE_SHIFT		= 7,
+
+	SES_STATUS_AUDIBLE_ALARM_MUTED_BYTE			= 2,
+	SES_STATUS_AUDIBLE_ALARM_MUTED_MASK			= 0x40,
+	SES_STATUS_AUDIBLE_ALARM_MUTED_SHIFT			= 6,
+
+	SES_STATUS_AUDIBLE_ALARM_REMIND_BYTE			= 2,
+	SES_STATUS_AUDIBLE_ALARM_REMIND_MASK			= 0x10,
+	SES_STATUS_AUDIBLE_ALARM_REMIND_SHIFT			= 4,
+
+	SES_STATUS_AUDIBLE_ALARM_TONE_INDICATOR_BYTE		= 2,
+	SES_STATUS_AUDIBLE_ALARM_TONE_INDICATOR_MASK		= 0x0F,
+	SES_STATUS_AUDIBLE_ALARM_TONE_INDICATOR_SHIFT		= 0,
+	SES_STATUS_AUDIBLE_ALARM_TONE_INDICATOR_INFO		= 0x08,
+	SES_STATUS_AUDIBLE_ALARM_TONE_INDICATOR_NON_CRIT	= 0x04,
+	SES_STATUS_AUDIBLE_ALARM_TONE_INDICATOR_CRIT		= 0x02,
+	SES_STATUS_AUDIBLE_ALARM_TONE_INDICATOR_UNRECOV		= 0x01
+};
+
+#define GEN_SES_STATUS_AUDIBLE_ALARM_ACCESSORS(LCASE, UCASE)	\
+    GEN_GETTER(ses_status_audible_alarm, SES_STATUS_AUDIBLE_ALARM, LCASE, UCASE)
+GEN_SES_STATUS_AUDIBLE_ALARM_ACCESSORS(ident,          IDENT)
+GEN_SES_STATUS_AUDIBLE_ALARM_ACCESSORS(fail,           FAIL)
+GEN_SES_STATUS_AUDIBLE_ALARM_ACCESSORS(rqst_mute,      RQST_MUTE)
+GEN_SES_STATUS_AUDIBLE_ALARM_ACCESSORS(muted,          MUTED)
+GEN_SES_STATUS_AUDIBLE_ALARM_ACCESSORS(remind,         REMIND)
+GEN_SES_STATUS_AUDIBLE_ALARM_ACCESSORS(tone_indicator, TONE_INDICATOR)
+#undef GEN_SES_STATUS_AUDIBLE_ALARM_ACCESSORS
+
+/*---------- Enclosure Services Statusler Electronics Status Element ---------*/
+struct ses_status_ecc_electronics {
+	struct ses_status_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_status_ecc_electronics_field_data {
+	SES_STATUS_ECC_ELECTRONICS_IDENT_BYTE		= 0,
+	SES_STATUS_ECC_ELECTRONICS_IDENT_MASK		= 0x80,
+	SES_STATUS_ECC_ELECTRONICS_IDENT_SHIFT		= 7,
+
+	SES_STATUS_ECC_ELECTRONICS_FAIL_BYTE		= 0,
+	SES_STATUS_ECC_ELECTRONICS_FAIL_MASK		= 0x40,
+	SES_STATUS_ECC_ELECTRONICS_FAIL_SHIFT		= 6,
+
+	SES_STATUS_ECC_ELECTRONICS_REPORT_BYTE		= 1,
+	SES_STATUS_ECC_ELECTRONICS_REPORT_MASK		= 0x01,
+	SES_STATUS_ECC_ELECTRONICS_REPORT_SHIFT		= 0,
+
+	SES_STATUS_ECC_ELECTRONICS_HOT_SWAP_BYTE	= 2,
+	SES_STATUS_ECC_ELECTRONICS_HOT_SWAP_MASK	= 0x80,
+	SES_STATUS_ECC_ELECTRONICS_HOT_SWAP_SHIFT	= 7
+};
+
+#define GEN_SES_STATUS_ECC_ELECTRONICS_ACCESSORS(LCASE, UCASE)		\
+    GEN_GETTER(ses_status_ecc_electronics, SES_STATUS_ECC_ELECTRONICS,	\
+		  LCASE, UCASE)
+GEN_SES_STATUS_ECC_ELECTRONICS_ACCESSORS(ident,     IDENT)
+GEN_SES_STATUS_ECC_ELECTRONICS_ACCESSORS(fail,      FAIL)
+GEN_SES_STATUS_ECC_ELECTRONICS_ACCESSORS(report,    REPORT)
+GEN_SES_STATUS_ECC_ELECTRONICS_ACCESSORS(hot_swap,  HOT_SWAP)
+#undef GEN_SES_STATUS_ECC_ELECTRONICS_ACCESSORS
+
+/*------------ SCSI Services Statusler Electronics Status Element ------------*/
+struct ses_status_scc_electronics {
+	struct ses_status_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_status_scc_electronics_field_data {
+	SES_STATUS_SCC_ELECTRONICS_IDENT_BYTE	= 0,
+	SES_STATUS_SCC_ELECTRONICS_IDENT_MASK	= 0x80,
+	SES_STATUS_SCC_ELECTRONICS_IDENT_SHIFT	= 7,
+
+	SES_STATUS_SCC_ELECTRONICS_FAIL_BYTE	= 0,
+	SES_STATUS_SCC_ELECTRONICS_FAIL_MASK	= 0x40,
+	SES_STATUS_SCC_ELECTRONICS_FAIL_SHIFT	= 6,
+
+	SES_STATUS_SCC_ELECTRONICS_REPORT_BYTE	= 1,
+	SES_STATUS_SCC_ELECTRONICS_REPORT_MASK	= 0x01,
+	SES_STATUS_SCC_ELECTRONICS_REPORT_SHIFT	= 0
+};
+
+#define GEN_SES_STATUS_SCC_ELECTRONICS_ACCESSORS(LCASE, UCASE)		\
+    GEN_GETTER(ses_status_scc_electronics, SES_STATUS_SCC_ELECTRONICS,	\
+		  LCASE, UCASE)
+GEN_SES_STATUS_SCC_ELECTRONICS_ACCESSORS(ident,     IDENT)
+GEN_SES_STATUS_SCC_ELECTRONICS_ACCESSORS(fail,      FAIL)
+GEN_SES_STATUS_SCC_ELECTRONICS_ACCESSORS(report,    REPORT)
+#undef GEN_SES_STATUS_SCC_ELECTRONICS_ACCESSORS
+
+/*--------------------- Nonvolatile Cache Status Element ---------------------*/
+struct ses_status_nv_cache {
+	struct ses_status_common common;
+	uint8_t bytes[1];
+	uint8_t cache_size[2];
+};
+
+enum ses_status_nv_cache_field_data {
+	SES_STATUS_NV_CACHE_IDENT_BYTE			= 0,
+	SES_STATUS_NV_CACHE_IDENT_MASK			= 0x80,
+	SES_STATUS_NV_CACHE_IDENT_SHIFT			= 7,
+
+	SES_STATUS_NV_CACHE_FAIL_BYTE			= 0,
+	SES_STATUS_NV_CACHE_FAIL_MASK			= 0x40,
+	SES_STATUS_NV_CACHE_FAIL_SHIFT			= 6,
+
+	SES_STATUS_NV_CACHE_SIZE_MULTIPLIER_BYTE	= 0,
+	SES_STATUS_NV_CACHE_SIZE_MULTIPLIER_MASK	= 0x03,
+	SES_STATUS_NV_CACHE_SIZE_MULTIPLIER_SHIFT	= 0,
+	SES_STATUS_NV_CACHE_SIZE_MULTIPLIER_BYTES	= 0x0,
+	SES_STATUS_NV_CACHE_SIZE_MULTIPLIER_KBYTES	= 0x1,
+	SES_STATUS_NV_CACHE_SIZE_MULTIPLIER_MBYTES	= 0x2,
+	SES_STATUS_NV_CACHE_SIZE_MULTIPLIER_GBYTES	= 0x3
+};
+
+#define GEN_SES_STATUS_NV_CACHE_ACCESSORS(LCASE, UCASE)		\
+    GEN_GETTER(ses_status_nv_cache, SES_STATUS_NV_CACHE, LCASE, UCASE)
+GEN_SES_STATUS_NV_CACHE_ACCESSORS(ident,           IDENT)
+GEN_SES_STATUS_NV_CACHE_ACCESSORS(fail,            FAIL)
+GEN_SES_STATUS_NV_CACHE_ACCESSORS(size_multiplier, SIZE_MULTIPLIER)
+#undef GEN_SES_STATUS_NV_CACHE_ACCESSORS
+
+static inline uintmax_t
+ses_status_nv_cache_get_cache_size(struct ses_status_nv_cache *elem)
+{
+	uintmax_t cache_size;
+	int multiplier;
+
+	/* Multiplier is in units of 2^10 */
+	cache_size = scsi_2btoul(elem->cache_size);
+	multiplier = 10 * ses_status_nv_cache_get_size_multiplier(elem);
+	return (cache_size << multiplier);
+}
+
+/*----------------- Invalid Operation Reason Status Element ------------------*/
+struct ses_status_invalid_op_reason {
+	struct ses_status_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_status_invalid_op_field_data {
+	SES_STATUS_INVALID_OP_REASON_TYPE_BYTE				= 0,
+	SES_STATUS_INVALID_OP_REASON_TYPE_MASK				= 0xC0,
+	SES_STATUS_INVALID_OP_REASON_TYPE_SHIFT				= 6,
+	SES_STATUS_INVALID_OP_REASON_TYPE_PC_ERROR			= 0x00,
+	SES_STATUS_INVALID_OP_REASON_TYPE_PF_ERROR			= 0x01,
+	SES_STATUS_INVALID_OP_REASON_TYPE_VS_ERROR			= 0x03,
+
+	SES_STATUS_INVALID_OP_REASON_PC_ERROR_PC_NOT_SUPPORTED_BYTE	= 0,
+	SES_STATUS_INVALID_OP_REASON_PC_ERROR_PC_NOT_SUPPORTED_MASK	= 0x01,
+	SES_STATUS_INVALID_OP_REASON_PC_ERROR_PC_NOT_SUPPORTED_SHIFT	= 0,
+
+	SES_STATUS_INVALID_OP_REASON_PF_ERROR_BIT_NUMBER_BYTE		= 0,
+	SES_STATUS_INVALID_OP_REASON_PF_ERROR_BIT_NUMBER_MASK		= 0x03,
+	SES_STATUS_INVALID_OP_REASON_PF_ERROR_BIT_NUMBER_SHIFT		= 0
+};
+
+#define GEN_SES_STATUS_INVALID_OP_REASON_ACCESSORS(LCASE, UCASE)	   \
+    GEN_GETTER(ses_status_invalid_op_reason, SES_STATUS_INVALID_OP_REASON, \
+	       LCASE, UCASE)
+GEN_SES_STATUS_INVALID_OP_REASON_ACCESSORS(type, TYPE)
+GEN_SES_STATUS_INVALID_OP_REASON_ACCESSORS(pc_error_pc_not_supported,
+					   PC_ERROR_PC_NOT_SUPPORTED)
+GEN_SES_STATUS_INVALID_OP_REASON_ACCESSORS(pf_error_bit_number,
+					   PF_ERROR_BIT_NUMBER)
+#undef GEN_SES_STATUS_INVALID_OP_ACCESSORS
+
+/*--------------- Uninterruptible Power Supply Status Element ----------------*/
+struct ses_status_ups {
+	struct ses_status_common common;
+	/* Minutes of remaining capacity. */
+	uint8_t battery_status;
+	uint8_t bytes[2];
+};
+
+enum ses_status_ups_field_data {
+	SES_STATUS_UPS_AC_LO_BYTE	= 0,
+	SES_STATUS_UPS_AC_LO_MASK	= 0x80,
+	SES_STATUS_UPS_AC_LO_SHIFT	= 7,
+
+	SES_STATUS_UPS_AC_HI_BYTE	= 0,
+	SES_STATUS_UPS_AC_HI_MASK	= 0x40,
+	SES_STATUS_UPS_AC_HI_SHIFT	= 6,
+
+	SES_STATUS_UPS_AC_QUAL_BYTE	= 0,
+	SES_STATUS_UPS_AC_QUAL_MASK	= 0x20,
+	SES_STATUS_UPS_AC_QUAL_SHIFT	= 5,
+
+	SES_STATUS_UPS_AC_FAIL_BYTE	= 0,
+	SES_STATUS_UPS_AC_FAIL_MASK	= 0x10,
+	SES_STATUS_UPS_AC_FAIL_SHIFT	= 4,
+
+	SES_STATUS_UPS_DC_FAIL_BYTE	= 0,
+	SES_STATUS_UPS_DC_FAIL_MASK	= 0x08,
+	SES_STATUS_UPS_DC_FAIL_SHIFT	= 3,
+
+	SES_STATUS_UPS_UPS_FAIL_BYTE	= 0,
+	SES_STATUS_UPS_UPS_FAIL_MASK	= 0x04,
+	SES_STATUS_UPS_UPS_FAIL_SHIFT	= 2,
+
+	SES_STATUS_UPS_WARN_BYTE	= 0,
+	SES_STATUS_UPS_WARN_MASK	= 0x02,
+	SES_STATUS_UPS_WARN_SHIFT	= 1,
+
+	SES_STATUS_UPS_INTF_FAIL_BYTE	= 0,
+	SES_STATUS_UPS_INTF_FAIL_MASK	= 0x01,
+	SES_STATUS_UPS_INTF_FAIL_SHIFT	= 0,
+
+	SES_STATUS_UPS_IDENT_BYTE	= 0,
+	SES_STATUS_UPS_IDENT_MASK	= 0x80,
+	SES_STATUS_UPS_IDENT_SHIFT	= 7,
+
+	SES_STATUS_UPS_FAIL_BYTE	= 1,
+	SES_STATUS_UPS_FAIL_MASK	= 0x40,
+	SES_STATUS_UPS_FAIL_SHIFT	= 6,
+
+	SES_STATUS_UPS_BATT_FAIL_BYTE	= 1,
+	SES_STATUS_UPS_BATT_FAIL_MASK	= 0x02,
+	SES_STATUS_UPS_BATT_FAIL_SHIFT	= 1,
+
+	SES_STATUS_UPS_BPF_BYTE		= 1,
+	SES_STATUS_UPS_BPF_MASK		= 0x01,
+	SES_STATUS_UPS_BPF_SHIFT	= 0
+};
+
+#define GEN_SES_STATUS_UPS_ACCESSORS(LCASE, UCASE)	\
+    GEN_GETTER(ses_status_ups, SES_STATUS_UPS, LCASE, UCASE)
+GEN_SES_STATUS_UPS_ACCESSORS(ac_lo,           AC_LO)
+GEN_SES_STATUS_UPS_ACCESSORS(ac_hi,            AC_HI)
+GEN_SES_STATUS_UPS_ACCESSORS(ac_qual,          AC_QUAL)
+GEN_SES_STATUS_UPS_ACCESSORS(ac_fail,          AC_FAIL)
+GEN_SES_STATUS_UPS_ACCESSORS(dc_fail,          DC_FAIL)
+GEN_SES_STATUS_UPS_ACCESSORS(ups_fail,         UPS_FAIL)
+GEN_SES_STATUS_UPS_ACCESSORS(warn,             WARN)
+GEN_SES_STATUS_UPS_ACCESSORS(intf_fail,        INTF_FAIL)
+GEN_SES_STATUS_UPS_ACCESSORS(ident,            IDENT)
+GEN_SES_STATUS_UPS_ACCESSORS(fail,             FAIL)
+GEN_SES_STATUS_UPS_ACCESSORS(batt_fail,        BATT_FAIL)
+GEN_SES_STATUS_UPS_ACCESSORS(bpf,              BPF)
+#undef GEN_SES_STATUS_UPS_ACCESSORS
+
+/*-------------------------- Display Status Element --------------------------*/
+struct ses_status_display {
+	struct ses_status_common common;
+	uint8_t bytes[1];
+	uint8_t display_character[2];
+};
+
+enum ses_status_display_field_data {
+	SES_STATUS_DISPLAY_IDENT_BYTE			= 0,
+	SES_STATUS_DISPLAY_IDENT_MASK			= 0x80,
+	SES_STATUS_DISPLAY_IDENT_SHIFT			= 7,
+
+	SES_STATUS_DISPLAY_FAIL_BYTE			= 0,
+	SES_STATUS_DISPLAY_FAIL_MASK			= 0x40,
+	SES_STATUS_DISPLAY_FAIL_SHIFT			= 6,
+
+	SES_STATUS_DISPLAY_DISPLAY_MODE_BYTE		= 0,
+	SES_STATUS_DISPLAY_DISPLAY_MODE_MASK		= 0x03,
+	SES_STATUS_DISPLAY_DISPLAY_MODE_SHIFT		= 6,
+	SES_STATUS_DISPLAY_DISPLAY_MODE_DC_FIELD_UNSUPP	= 0x0,
+	SES_STATUS_DISPLAY_DISPLAY_MODE_DC_FIELD_SUPP	= 0x1,
+	SES_STATUS_DISPLAY_DISPLAY_MODE_DC_FIELD	= 0x2
+};
+
+#define GEN_SES_STATUS_DISPLAY_ACCESSORS(LCASE, UCASE)	\
+    GEN_GETTER(ses_status_display, SES_STATUS_DISPLAY, LCASE, UCASE)
+GEN_SES_STATUS_DISPLAY_ACCESSORS(ident,        IDENT)
+GEN_SES_STATUS_DISPLAY_ACCESSORS(fail,         FAIL)
+GEN_SES_STATUS_DISPLAY_ACCESSORS(display_mode, DISPLAY_MODE)
+#undef GEN_SES_STATUS_DISPLAY_ACCESSORS
+
+/*----------------------- Key Pad Entry Status Element -----------------------*/
+struct ses_status_key_pad_entry {
+	struct ses_status_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_status_key_pad_entry_field_data {
+	SES_STATUS_KEY_PAD_ENTRY_IDENT_BYTE	= 0,
+	SES_STATUS_KEY_PAD_ENTRY_IDENT_MASK	= 0x80,
+	SES_STATUS_KEY_PAD_ENTRY_IDENT_SHIFT	= 7,
+
+	SES_STATUS_KEY_PAD_ENTRY_FAIL_BYTE	= 0,
+	SES_STATUS_KEY_PAD_ENTRY_FAIL_MASK	= 0x40,
+	SES_STATUS_KEY_PAD_ENTRY_FAIL_SHIFT	= 6
+};
+
+#define GEN_SES_STATUS_KEY_PAD_ENTRY_ACCESSORS(LCASE, UCASE)	\
+    GEN_GETTER(ses_status_key_pad_entry, SES_STATUS_KEY_PAD_ENTRY, LCASE, UCASE)
+GEN_SES_STATUS_KEY_PAD_ENTRY_ACCESSORS(ident, IDENT)
+GEN_SES_STATUS_KEY_PAD_ENTRY_ACCESSORS(fail,  FAIL)
+#undef GEN_SES_STATUS_KEY_PAD_ENTRY_ACCESSORS
+
+/*------------------------- Enclosure Status Element -------------------------*/
+struct ses_status_enclosure {
+	struct ses_status_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_status_enclosure_field_data {
+	SES_STATUS_ENCLOSURE_IDENT_BYTE					= 0,
+	SES_STATUS_ENCLOSURE_IDENT_MASK					= 0x80,
+	SES_STATUS_ENCLOSURE_IDENT_SHIFT				= 7,
+
+	SES_STATUS_ENCLOSURE_TIME_UNTIL_POWER_CYCLE_BYTE		= 1,
+	SES_STATUS_ENCLOSURE_TIME_UNTIL_POWER_CYCLE_MASK		= 0xFC,
+	SES_STATUS_ENCLOSURE_TIME_UNTIL_POWER_CYCLE_SHIFT		= 2,
+
+	SES_STATUS_ENCLOSURE_FAIL_BYTE					= 1,
+	SES_STATUS_ENCLOSURE_FAIL_MASK					= 0x02,
+	SES_STATUS_ENCLOSURE_FAIL_SHIFT					= 1,
+
+	SES_STATUS_ENCLOSURE_WARN_BYTE					= 1,
+	SES_STATUS_ENCLOSURE_WARN_MASK					= 0x01,
+	SES_STATUS_ENCLOSURE_WARN_SHIFT					= 0,
+
+	SES_STATUS_ENCLOSURE_REQUESTED_POWER_OFF_DURATION_BYTE		= 2,
+	SES_STATUS_ENCLOSURE_REQUESTED_POWER_OFF_DURATION_MASK		= 0xFC,
+	SES_STATUS_ENCLOSURE_REQUESTED_POWER_OFF_DURATION_SHIFT		= 2,
+	SES_STATUS_ENCLOSURE_REQUESTED_POWER_OFF_DURATION_MAX_AUTO	= 60,
+	SES_STATUS_ENCLOSURE_REQUESTED_POWER_OFF_DURATION_MANUAL	= 63,
+
+	SES_STATUS_ENCLOSURE_REQUESTED_FAIL_BYTE			= 2,
+	SES_STATUS_ENCLOSURE_REQUESTED_FAIL_MASK			= 0x02,
+	SES_STATUS_ENCLOSURE_REQUESTED_FAIL_SHIFT			= 1,
+
+	SES_STATUS_ENCLOSURE_REQUESTED_WARN_BYTE			= 2,
+	SES_STATUS_ENCLOSURE_REQUESTED_WARN_MASK			= 0x01,
+	SES_STATUS_ENCLOSURE_REQUESTED_WARN_SHIFT			= 0
+};
+
+#define GEN_SES_STATUS_ENCLOSURE_ACCESSORS(LCASE, UCASE)		\
+    GEN_GETTER(ses_status_enclosure, SES_STATUS_ENCLOSURE, LCASE, UCASE)
+GEN_SES_STATUS_ENCLOSURE_ACCESSORS(ident,          IDENT)
+GEN_SES_STATUS_ENCLOSURE_ACCESSORS(time_until_power_cycle,
+				   TIME_UNTIL_POWER_CYCLE)
+GEN_SES_STATUS_ENCLOSURE_ACCESSORS(fail,           FAIL)
+GEN_SES_STATUS_ENCLOSURE_ACCESSORS(warn,           WARN)
+GEN_SES_STATUS_ENCLOSURE_ACCESSORS(requested_power_off_duration,
+				   REQUESTED_POWER_OFF_DURATION)
+GEN_SES_STATUS_ENCLOSURE_ACCESSORS(requested_fail, REQUESTED_FAIL)
+GEN_SES_STATUS_ENCLOSURE_ACCESSORS(requested_warn, REQUESTED_WARN)
+#undef GEN_SES_STATUS_ENCLOSURE_ACCESSORS
+
+/*------------------- SCSI Port/Transceiver Status Element -------------------*/
+struct ses_status_scsi_port_or_xcvr {
+	struct ses_status_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_status_scsi_port_or_xcvr_field_data {
+	SES_STATUS_SCSI_PORT_OR_XCVR_IDENT_BYTE		= 0,
+	SES_STATUS_SCSI_PORT_OR_XCVR_IDENT_MASK		= 0x80,
+	SES_STATUS_SCSI_PORT_OR_XCVR_IDENT_SHIFT	= 7,
+
+	SES_STATUS_SCSI_PORT_OR_XCVR_FAIL_BYTE		= 0,
+	SES_STATUS_SCSI_PORT_OR_XCVR_FAIL_MASK		= 0x40,
+	SES_STATUS_SCSI_PORT_OR_XCVR_FAIL_SHIFT		= 6,
+
+	SES_STATUS_SCSI_PORT_OR_XCVR_REPORT_BYTE	= 1,
+	SES_STATUS_SCSI_PORT_OR_XCVR_REPORT_MASK	= 0x01,
+	SES_STATUS_SCSI_PORT_OR_XCVR_REPORT_SHIFT	= 0,
+
+	SES_STATUS_SCSI_PORT_OR_XCVR_DISABLED_BYTE	= 2,
+	SES_STATUS_SCSI_PORT_OR_XCVR_DISABLED_MASK	= 0x10,
+	SES_STATUS_SCSI_PORT_OR_XCVR_DISABLED_SHIFT	= 4,
+
+	SES_STATUS_SCSI_PORT_OR_XCVR_LOL_BYTE		= 2,
+	SES_STATUS_SCSI_PORT_OR_XCVR_LOL_MASK		= 0x02,
+	SES_STATUS_SCSI_PORT_OR_XCVR_LOL_SHIFT		= 1,
+
+	SES_STATUS_SCSI_PORT_OR_XCVR_XMIT_FAIL_BYTE	= 2,
+	SES_STATUS_SCSI_PORT_OR_XCVR_XMIT_FAIL_MASK	= 0x01,
+	SES_STATUS_SCSI_PORT_OR_XCVR_XMIT_FAIL_SHIFT	= 0
+};
+
+#define GEN_SES_STATUS_SCSI_PORT_OR_XCVR_ACCESSORS(LCASE, UCASE)	 \
+    GEN_GETTER(ses_status_scsi_port_or_xcvr, SES_STATUS_SCSI_PORT_OR_XCVR,\
+	       LCASE, UCASE)
+GEN_SES_STATUS_SCSI_PORT_OR_XCVR_ACCESSORS(ident,     IDENT)
+GEN_SES_STATUS_SCSI_PORT_OR_XCVR_ACCESSORS(fail,      FAIL)
+GEN_SES_STATUS_SCSI_PORT_OR_XCVR_ACCESSORS(report,    REPORT)
+GEN_SES_STATUS_SCSI_PORT_OR_XCVR_ACCESSORS(disable,   DISABLED)
+GEN_SES_STATUS_SCSI_PORT_OR_XCVR_ACCESSORS(lol,       LOL)
+GEN_SES_STATUS_SCSI_PORT_OR_XCVR_ACCESSORS(xmit_fail, XMIT_FAIL)
+#undef GEN_SES_STATUS_SCSI_PORT_OR_XCVR_ACCESSORS
+
+/*------------------------- Language Status Element --------------------------*/
+struct ses_status_language {
+	struct ses_status_common common;
+	uint8_t bytes[1];
+	uint8_t language_code[2];
+};
+
+enum ses_status_language_field_data {
+	SES_STATUS_LANGUAGE_IDENT_BYTE	= 0,
+	SES_STATUS_LANGUAGE_IDENT_MASK	= 0x80,
+	SES_STATUS_LANGUAGE_IDENT_SHIFT	= 7
+};
+
+#define GEN_SES_STATUS_LANGUAGE_ACCESSORS(LCASE, UCASE)		 \
+    GEN_GETTER(ses_status_language, SES_STATUS_LANGUAGE, LCASE, UCASE)
+GEN_SES_STATUS_LANGUAGE_ACCESSORS(ident, IDENT)
+#undef GEN_SES_STATUS_LANGUAGE_ACCESSORS
+
+/*-------------------- Communication Port Status Element ---------------------*/
+struct ses_status_comm_port {
+	struct ses_status_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_status_comm_port_field_data {
+	SES_STATUS_COMM_PORT_IDENT_BYTE		= 0,
+	SES_STATUS_COMM_PORT_IDENT_MASK		= 0x80,
+	SES_STATUS_COMM_PORT_IDENT_SHIFT	= 7,
+
+	SES_STATUS_COMM_PORT_FAIL_BYTE		= 0,
+	SES_STATUS_COMM_PORT_FAIL_MASK		= 0x40,
+	SES_STATUS_COMM_PORT_FAIL_SHIFT		= 6,
+
+	SES_STATUS_COMM_PORT_DISABLED_BYTE	= 2,
+	SES_STATUS_COMM_PORT_DISABLED_MASK	= 0x01,
+	SES_STATUS_COMM_PORT_DISABLED_SHIFT	= 0
+};
+
+#define GEN_SES_STATUS_COMM_PORT_ACCESSORS(LCASE, UCASE)		 \
+    GEN_GETTER(ses_status_comm_port, SES_STATUS_COMM_PORT, LCASE, UCASE)
+GEN_SES_STATUS_COMM_PORT_ACCESSORS(ident,    IDENT)
+GEN_SES_STATUS_COMM_PORT_ACCESSORS(fail,     FAIL)
+GEN_SES_STATUS_COMM_PORT_ACCESSORS(disabled, DISABLED)
+#undef GEN_SES_STATUS_COMM_PORT_ACCESSORS
+
+/*---------------------- Voltage Sensor Status Element -----------------------*/
+struct ses_status_voltage_sensor {
+	struct ses_status_common common;
+	uint8_t bytes[1];
+	uint8_t voltage[2];
+};
+
+enum ses_status_voltage_sensor_field_data {
+	SES_STATUS_VOLTAGE_SENSOR_IDENT_BYTE		= 0,
+	SES_STATUS_VOLTAGE_SENSOR_IDENT_MASK		= 0x80,
+	SES_STATUS_VOLTAGE_SENSOR_IDENT_SHIFT		= 7,
+
+	SES_STATUS_VOLTAGE_SENSOR_FAIL_BYTE		= 0,
+	SES_STATUS_VOLTAGE_SENSOR_FAIL_MASK		= 0x40,
+	SES_STATUS_VOLTAGE_SENSOR_FAIL_SHIFT		= 6,
+
+	SES_STATUS_VOLTAGE_SENSOR_WARN_OVER_BYTE	= 0,
+	SES_STATUS_VOLTAGE_SENSOR_WARN_OVER_MASK	= 0x08,
+	SES_STATUS_VOLTAGE_SENSOR_WARN_OVER_SHIFT	= 3,
+
+	SES_STATUS_VOLTAGE_SENSOR_WARN_UNDER_BYTE	= 0,
+	SES_STATUS_VOLTAGE_SENSOR_WARN_UNDER_MASK	= 0x04,
+	SES_STATUS_VOLTAGE_SENSOR_WARN_UNDER_SHIFT	= 2,
+
+	SES_STATUS_VOLTAGE_SENSOR_CRIT_OVER_BYTE	= 0,
+	SES_STATUS_VOLTAGE_SENSOR_CRIT_OVER_MASK	= 0x02,
+	SES_STATUS_VOLTAGE_SENSOR_CRIT_OVER_SHIFT	= 1,
+
+	SES_STATUS_VOLTAGE_SENSOR_CRIT_UNDER_BYTE	= 0,
+	SES_STATUS_VOLTAGE_SENSOR_CRIT_UNDER_MASK	= 0x01,
+	SES_STATUS_VOLTAGE_SENSOR_CRIT_UNDER_SHIFT	= 0
+};
+
+#define GEN_SES_STATUS_VOLTAGE_SENSOR_ACCESSORS(LCASE, UCASE)		\
+    GEN_GETTER(ses_status_voltage_sensor, SES_STATUS_VOLTAGE_SENSOR,	\
+		  LCASE, UCASE)
+GEN_SES_STATUS_VOLTAGE_SENSOR_ACCESSORS(ident,      IDENT)
+GEN_SES_STATUS_VOLTAGE_SENSOR_ACCESSORS(fail,       FAIL)
+GEN_SES_STATUS_VOLTAGE_SENSOR_ACCESSORS(warn_over,  WARN_OVER)
+GEN_SES_STATUS_VOLTAGE_SENSOR_ACCESSORS(warn_under, WARN_UNDER)
+GEN_SES_STATUS_VOLTAGE_SENSOR_ACCESSORS(crit_over,  CRIT_OVER)
+GEN_SES_STATUS_VOLTAGE_SENSOR_ACCESSORS(crit_under, CRIT_UNDER)
+#undef GEN_SES_STATUS_VOLTAGE_SENSOR_ACCESSORS
+
+/*---------------------- Current Sensor Status Element -----------------------*/
+struct ses_status_current_sensor {
+	struct ses_status_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_status_current_sensor_field_data {
+	SES_STATUS_CURRENT_SENSOR_IDENT_BYTE		= 0,
+	SES_STATUS_CURRENT_SENSOR_IDENT_MASK		= 0x80,
+	SES_STATUS_CURRENT_SENSOR_IDENT_SHIFT		= 7,
+
+	SES_STATUS_CURRENT_SENSOR_FAIL_BYTE		= 0,
+	SES_STATUS_CURRENT_SENSOR_FAIL_MASK		= 0x40,
+	SES_STATUS_CURRENT_SENSOR_FAIL_SHIFT		= 6,
+
+	SES_STATUS_CURRENT_SENSOR_WARN_OVER_BYTE	= 0,
+	SES_STATUS_CURRENT_SENSOR_WARN_OVER_MASK	= 0x08,
+	SES_STATUS_CURRENT_SENSOR_WARN_OVER_SHIFT	= 3,
+
+	SES_STATUS_CURRENT_SENSOR_CRIT_OVER_BYTE	= 0,
+	SES_STATUS_CURRENT_SENSOR_CRIT_OVER_MASK	= 0x02,
+	SES_STATUS_CURRENT_SENSOR_CRIT_OVER_SHIFT	= 1
+};
+
+#define GEN_SES_STATUS_CURRENT_SENSOR_ACCESSORS(LCASE, UCASE)		\
+    GEN_GETTER(ses_status_current_sensor, SES_STATUS_CURRENT_SENSOR,	\
+		  LCASE, UCASE)
+GEN_SES_STATUS_CURRENT_SENSOR_ACCESSORS(ident,      IDENT)
+GEN_SES_STATUS_CURRENT_SENSOR_ACCESSORS(fail,       FAIL)
+GEN_SES_STATUS_CURRENT_SENSOR_ACCESSORS(warn_over,  WARN_OVER)
+GEN_SES_STATUS_CURRENT_SENSOR_ACCESSORS(crit_over,  CRIT_OVER)
+#undef GEN_SES_STATUS_CURRENT_SENSOR_ACCESSORS
+
+/*--------------------- SCSI Target Port Status Element ----------------------*/
+struct ses_status_target_port {
+	struct ses_status_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_status_scsi_target_port_field_data {
+	SES_STATUS_TARGET_PORT_IDENT_BYTE	= 0,
+	SES_STATUS_TARGET_PORT_IDENT_MASK	= 0x80,
+	SES_STATUS_TARGET_PORT_IDENT_SHIFT	= 7,
+
+	SES_STATUS_TARGET_PORT_FAIL_BYTE	= 0,
+	SES_STATUS_TARGET_PORT_FAIL_MASK	= 0x40,
+	SES_STATUS_TARGET_PORT_FAIL_SHIFT	= 6,
+
+	SES_STATUS_TARGET_PORT_REPORT_BYTE	= 1,
+	SES_STATUS_TARGET_PORT_REPORT_MASK	= 0x01,
+	SES_STATUS_TARGET_PORT_REPORT_SHIFT	= 0,
+
+	SES_STATUS_TARGET_PORT_ENABLED_BYTE	= 2,
+	SES_STATUS_TARGET_PORT_ENABLED_MASK	= 0x01,
+	SES_STATUS_TARGET_PORT_ENABLED_SHIFT	= 0
+};
+
+#define GEN_SES_STATUS_TARGET_PORT_ACCESSORS(LCASE, UCASE)	\
+    GEN_GETTER(ses_status_target_port, SES_STATUS_TARGET_PORT, LCASE, UCASE)
+GEN_SES_STATUS_TARGET_PORT_ACCESSORS(ident,   IDENT)
+GEN_SES_STATUS_TARGET_PORT_ACCESSORS(fail,    FAIL)
+GEN_SES_STATUS_TARGET_PORT_ACCESSORS(report,  REPORT)
+GEN_SES_STATUS_TARGET_PORT_ACCESSORS(enabled, ENABLED)
+#undef GEN_SES_STATUS_TARGET_PORT_ACCESSORS
+
+/*-------------------- SCSI Initiator Port Status Element --------------------*/
+struct ses_status_initiator_port {
+	struct ses_status_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_status_scsi_initiator_port_field_data {
+	SES_STATUS_INITIATOR_PORT_IDENT_BYTE	= 0,
+	SES_STATUS_INITIATOR_PORT_IDENT_MASK	= 0x80,
+	SES_STATUS_INITIATOR_PORT_IDENT_SHIFT	= 7,
+
+	SES_STATUS_INITIATOR_PORT_FAIL_BYTE	= 0,
+	SES_STATUS_INITIATOR_PORT_FAIL_MASK	= 0x40,
+	SES_STATUS_INITIATOR_PORT_FAIL_SHIFT	= 6,
+
+	SES_STATUS_INITIATOR_PORT_REPORT_BYTE	= 1,
+	SES_STATUS_INITIATOR_PORT_REPORT_MASK	= 0x01,
+	SES_STATUS_INITIATOR_PORT_REPORT_SHIFT	= 0,
+
+	SES_STATUS_INITIATOR_PORT_ENABLED_BYTE	= 2,
+	SES_STATUS_INITIATOR_PORT_ENABLED_MASK	= 0x01,
+	SES_STATUS_INITIATOR_PORT_ENABLED_SHIFT	= 0
+};
+
+#define GEN_SES_STATUS_INITIATOR_PORT_ACCESSORS(LCASE, UCASE)		\
+    GEN_GETTER(ses_status_initiator_port, SES_STATUS_INITIATOR_PORT,	\
+	       LCASE, UCASE)
+GEN_SES_STATUS_INITIATOR_PORT_ACCESSORS(ident,   IDENT)
+GEN_SES_STATUS_INITIATOR_PORT_ACCESSORS(fail,    FAIL)
+GEN_SES_STATUS_INITIATOR_PORT_ACCESSORS(report,  REPORT)
+GEN_SES_STATUS_INITIATOR_PORT_ACCESSORS(enabled, ENABLED)
+#undef GEN_SES_STATUS_INITIATOR_PORT_ACCESSORS
+
+/*-------------------- Simple Subenclosure Status Element --------------------*/
+struct ses_status_simple_subses {
+	struct ses_status_common common;
+	uint8_t bytes[2];
+	uint8_t short_enclosure_status;
+};
+
+enum ses_status_simple_subses_field_data {
+	SES_STATUS_SIMPlE_SUBSES_IDENT_BYTE	= 0,
+	SES_STATUS_SIMPlE_SUBSES_IDENT_MASK	= 0x80,
+	SES_STATUS_SIMPlE_SUBSES_IDENT_SHIFT	= 7,
+
+	SES_STATUS_SIMPlE_SUBSES_FAIL_BYTE	= 0,
+	SES_STATUS_SIMPlE_SUBSES_FAIL_MASK	= 0x40,
+	SES_STATUS_SIMPlE_SUBSES_FAIL_SHIFT	= 6
+};
+
+#define GEN_SES_STATUS_SIMPlE_SUBSES_ACCESSORS(LCASE, UCASE)		\
+    GEN_GETTER(ses_status_simple_subses, SES_STATUS_SIMPlE_SUBSES,	\
+		  LCASE, UCASE)
+GEN_SES_STATUS_SIMPlE_SUBSES_ACCESSORS(ident, IDENT)
+GEN_SES_STATUS_SIMPlE_SUBSES_ACCESSORS(fail,  FAIL)
+#undef GEN_SES_STATUS_SIMPlE_SUBSES_ACCESSORS
+
+/*----------------------- SAS Expander Status Element ------------------------*/
+struct ses_status_sas_expander {
+	struct ses_status_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_status_sas_expander_field_data {
+	SES_STATUS_SAS_EXPANDER_IDENT_BYTE	= 0,
+	SES_STATUS_SAS_EXPANDER_IDENT_MASK	= 0x80,
+	SES_STATUS_SAS_EXPANDER_IDENT_SHIFT	= 7,
+
+	SES_STATUS_SAS_EXPANDER_FAIL_BYTE	= 0,
+	SES_STATUS_SAS_EXPANDER_FAIL_MASK	= 0x40,
+	SES_STATUS_SAS_EXPANDER_FAIL_SHIFT	= 6
+};
+
+#define GEN_SES_STATUS_SAS_EXPANDER_ACCESSORS(LCASE, UCASE)	\
+    GEN_GETTER(ses_status_sas_expander, SES_STATUS_SAS_EXPANDER,	LCASE, UCASE)
+GEN_SES_STATUS_SAS_EXPANDER_ACCESSORS(ident, IDENT)
+GEN_SES_STATUS_SAS_EXPANDER_ACCESSORS(fail,  FAIL)
+#undef GEN_SES_STATUS_SAS_EXPANDER_ACCESSORS
+
+/*----------------------- SAS Connector Status Element -----------------------*/
+struct ses_status_sas_connector {
+	struct ses_status_common common;
+	uint8_t bytes[3];
+};
+
+enum ses_status_sas_connector_field_data {
+	SES_STATUS_SAS_CONNECTOR_IDENT_BYTE		= 0,
+	SES_STATUS_SAS_CONNECTOR_IDENT_MASK		= 0x80,
+	SES_STATUS_SAS_CONNECTOR_IDENT_SHIFT		= 7,
+
+	SES_STATUS_SAS_CONNECTOR_TYPE_BYTE		= 0,
+	SES_STATUS_SAS_CONNECTOR_TYPE_MASK		= 0x7F,
+	SES_STATUS_SAS_CONNECTOR_TYPE_SHIFT		= 0,
+
+	SES_STATUS_SAS_CONNECTOR_PHYS_LINK_BYTE		= 1,
+	SES_STATUS_SAS_CONNECTOR_PHYS_LINK_MASK		= 0xFF,
+	SES_STATUS_SAS_CONNECTOR_PHYS_LINK_SHIFT	= 0,
+	SES_STATUS_SAS_CONNECTOR_PHYS_LINK_ALL		= 0xFF,
+
+	SES_ST